J'écris un test qui dépend des résultats d'une méthode d'extension, mais je ne veux pas qu'un échec futur de cette méthode d'extension brise jamais ce test. Se moquer de ce résultat semblait le choix évident, mais Moq ne semble pas offrir un moyen de remplacer une méthode statique (une exigence pour une méthode d'extension). Il y a une idée similaire avec Moq.Protected et Moq.Stub, mais ils ne semblent rien offrir pour ce scénario. Est-ce que je manque quelque chose ou devrais-je procéder d'une manière différente?
Voici un exemple trivial qui échoue avec l'habituelle "Attente non valide sur un membre non remplaçable" . C'est un mauvais exemple de besoin de se moquer d'une méthode d'extension, mais cela devrait le faire.
public class SomeType {
int Id { get; set; }
}
var ListMock = new Mock<List<SomeType>>();
ListMock.Expect(l => l.FirstOrDefault(st => st.Id == 5))
.Returns(new SomeType { Id = 5 });
Comme pour tous les accros de TypeMock qui pourraient suggérer que j'utilise Isolator à la place: j'apprécie l'effort car il semble que TypeMock pourrait faire le travail les yeux bandés et en état d'ébriété, mais notre budget n'augmente pas de si tôt.
la source
Réponses:
Les méthodes d'extension ne sont que des méthodes statiques déguisées. Les frameworks moqueurs tels que Moq ou Rhinomocks ne peuvent créer que des instances factices d'objets, cela signifie qu'il n'est pas possible de se moquer des méthodes statiques.
la source
Si vous pouvez modifier le code des méthodes d'extension, vous pouvez le coder comme ceci pour pouvoir tester:
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; public static class MyExtensions { public static IMyImplementation Implementation = new MyImplementation(); public static string MyMethod(this object obj) { return Implementation.MyMethod(obj); } } public interface IMyImplementation { string MyMethod(object obj); } public class MyImplementation : IMyImplementation { public string MyMethod(object obj) { return "Hello World!"; } }
Les méthodes d'extension ne sont donc qu'un wrapper autour de l'interface d'implémentation.
(Vous pouvez utiliser uniquement la classe d'implémentation sans méthodes d'extension qui sont en quelque sorte du sucre syntaxique.)
Et vous pouvez vous moquer de l'interface d'implémentation et la définir comme implémentation pour la classe d'extensions.
public class MyClassUsingExtensions { public string ReturnStringForObject(object obj) { return obj.MyMethod(); } } [TestClass] public class MyTests { [TestMethod] public void MyTest() { // Given: //------- var mockMyImplementation = new Mock<IMyImplementation>(); MyExtensions.Implementation = mockMyImplementation.Object; var myClassUsingExtensions = new MyClassUsingExtensions(); // When: //------- var myObject = new Object(); myClassUsingExtensions.ReturnStringForObject(myObject); //Then: //------- // This would fail because you cannot test for the extension method //mockMyImplementation.Verify(m => m.MyMethod()); // This is success because you test for the mocked implementation interface mockMyImplementation.Verify(m => m.MyMethod(myObject)); } }
la source
Je sais que cette question n'a pas été active depuis environ un an, mais Microsoft a publié un cadre pour gérer exactement cela appelé Moles .
Voici également quelques tutoriels:
la source
J'ai créé une classe wrapper pour les méthodes d'extension dont je devais me moquer.
public static class MyExtensions { public static string MyExtension<T>(this T obj) { return "Hello World!"; } } public interface IExtensionMethodsWrapper { string MyExtension<T>(T myObj); } public class ExtensionMethodsWrapper : IExtensionMethodsWrapper { public string MyExtension<T>(T myObj) { return myObj.MyExtension(); } }
Ensuite, vous pouvez vous moquer des méthodes wrapper dans vos tests et code avec votre conteneur IOC.
la source
Pour les méthodes d'extension, j'utilise normalement l'approche suivante:
public static class MyExtensions { public static Func<int,int, int> _doSumm = (x, y) => x + y; public static int Summ(this int x, int y) { return _doSumm(x, y); } }
Cela permet d'injecter _doSumm assez facilement.
la source
La meilleure chose que vous puissiez faire est de fournir une implémentation personnalisée pour le type qui a la méthode d'extension, par exemple:
[Fact] public class Tests { public void ShouldRunOk() { var service = new MyService(new FakeWebHostEnvironment()); // Service.DoStuff() internally calls the SomeExtensionFunction() on IWebHostEnvironment // Here it works just fine as we provide a custom implementation of that interface service.DoStuff().Should().NotBeNull(); } } public class FakeWebHostEnvironment : IWebHostEnvironment { /* IWebHostEnvironment implementation */ public bool SomeExtensionFunction() { return false; } }
la source