Piszę test, który zależy od wyników metody rozszerzającej, ale nie chcę, aby przyszła awaria tej metody rozszerzającej kiedykolwiek przerwała ten test. Kpienie z tego wyniku wydawało się oczywistym wyborem, ale Moq nie wydaje się oferować sposobu na zastąpienie metody statycznej (wymóg dla metody rozszerzającej). Podobny pomysł jest z Moq.Protected i Moq.Stub, ale wydaje się, że nie oferują one niczego w tym scenariuszu. Czy czegoś mi brakuje, czy powinienem zająć się tym inaczej?
Oto trywialny przykład, który kończy się niepowodzeniem ze zwykłym „Nieprawidłowym oczekiwaniem na nieprzekraczalny element członkowski” . To zły przykład potrzeby kpienia z metody rozszerzającej, ale powinno.
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 });
Jeśli chodzi o każdego ćpuna TypeMock, który mógłby zasugerować, żebym zamiast tego użył Izolatora: doceniam wysiłek, ponieważ wygląda na to, że TypeMock mógłby wykonać pracę z zawiązanymi oczami i nietrzeźwym, ale nasz budżet nie zwiększa się w najbliższym czasie.
źródło
Odpowiedzi:
Metody rozszerzające to po prostu metody statyczne w przebraniu. Mockowanie frameworków, takich jak Moq czy Rhinomocks, może tworzyć tylko pozorowane instancje obiektów, co oznacza, że mockowanie metod statycznych nie jest możliwe.
źródło
Jeśli możesz zmienić kod metod rozszerzenia, możesz go zakodować w ten sposób, aby móc testować:
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!"; } }
Zatem metody rozszerzające są jedynie otoką wokół interfejsu implementacji.
(Możesz użyć tylko klasy implementacji bez metod rozszerzających, które są rodzajem cukru składniowego).
Możesz też mockować interfejs implementacji i ustawić go jako implementację dla klasy rozszerzeń.
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)); } }
źródło
Wiem, że to pytanie nie było aktywne od około roku, ale Microsoft wydał framework do obsługi dokładnie tego, zwanego Moles .
Oto kilka samouczków:
źródło
Utworzyłem klasę opakowującą dla metod rozszerzających, których potrzebowałem do mockowania.
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(); } }
Następnie możesz mockować metody opakowania w testach i kodować za pomocą kontenera IOC.
źródło
W przypadku metod rozszerzających zwykle używam następującego podejścia:
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); } }
Pozwala dość łatwo wstrzyknąć _doSumm.
źródło
Najlepszą rzeczą, jaką możesz zrobić, jest zapewnienie niestandardowej implementacji dla typu, który ma metodę rozszerzenia, np .:
[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; } }
źródło