Я пишу тест, который зависит от результатов метода расширения, но я не хочу, чтобы будущий сбой этого метода расширения когда-либо нарушил этот тест. Насмешка над этим результатом казалась очевидным выбором, но Moq, похоже, не предлагает способа переопределить статический метод (требование для метода расширения). Аналогичная идея есть с Moq.Protected и Moq.Stub, но они, похоже, ничего не предлагают для этого сценария. Я что-то упускаю или мне следует поступить иначе?
Вот тривиальный пример, который не соответствует обычному «Неверное ожидание для непереопределяемого члена» . Это плохой пример необходимости имитировать метод расширения, но он должен работать.
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 });
Что касается наркоманов TypeMock, которые могут посоветовать мне вместо этого использовать Isolator: я ценю усилия, поскольку похоже, что TypeMock может выполнять работу с завязанными глазами и в нетрезвом виде, но наш бюджет в ближайшее время не увеличится.
источник
Ответы:
Методы расширения - это всего лишь замаскированные статические методы. Фреймворки имитации, такие как Moq или Rhinomocks, могут создавать только имитирующие экземпляры объектов, это означает, что имитация статических методов невозможна.
источник
Если вы можете изменить код методов расширения, вы можете закодировать его следующим образом, чтобы иметь возможность тестировать:
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!"; } }
Таким образом, методы расширения - это лишь оболочка интерфейса реализации.
(Вы можете использовать только класс реализации без методов расширения, которые являются своего рода синтаксическим сахаром.)
И вы можете смоделировать интерфейс реализации и установить его как реализацию для класса расширений.
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)); } }
источник
Я знаю, что этот вопрос не был активен около года, но Microsoft выпустила платформу для обработки именно этого, называемую Moles .
Вот несколько уроков:
источник
Я создал класс-оболочку для методов расширения, которые мне нужно было издеваться.
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(); } }
Затем вы можете имитировать методы оболочки в своих тестах и кодировать с помощью контейнера IOC.
источник
Для методов расширения я обычно использую следующий подход:
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); } }
Это позволяет довольно легко внедрить _doSumm.
источник
Лучшее, что вы можете сделать, - это предоставить настраиваемую реализацию для типа, который имеет метод расширения, например:
[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; } }
источник