2010-02-19 5 views
102

У меня есть существовавшие ранее интерфейс ...Mocking Методы расширения с Moq

public interface ISomeInterface 
{ 
    void SomeMethod(); 
} 

и я расширил этот разрыв клавиатуры, используя подмешать ...

public static class SomeInterfaceExtensions 
{ 
    public static void AnotherMethod(this ISomeInterface someInterface) 
    { 
     // Implementation here 
    } 
} 

У меня есть класс Thats называют это который я хочу проверить ...

public class Caller 
{ 
    private readonly ISomeInterface someInterface; 

    public Caller(ISomeInterface someInterface) 
    { 
     this.someInterface = someInterface; 
    } 

    public void Main() 
    { 
     someInterface.AnotherMethod(); 
    } 
} 

и тест, где я хотел бы, чтобы дразнить интерфейс и проверить вызов метода расширения ...

[Test] 
    public void Main_BasicCall_CallsAnotherMethod() 
    { 
     // Arrange 
     var someInterfaceMock = new Mock<ISomeInterface>(); 
     someInterfaceMock.Setup(x => x.AnotherMethod()).Verifiable(); 

     var caller = new Caller(someInterfaceMock.Object); 

     // Act 
     caller.Main(); 

     // Assert 
     someInterfaceMock.Verify(); 
    } 

Запуск этого теста, однако генерирует исключение ...

System.ArgumentException: Invalid setup on a non-member method: 
x => x.AnotherMethod() 

Мой вопрос, есть хороший способ, чтобы дразнить из вызова подмешать?

+2

В моем опыте термины mixin и методы расширения - это отдельные вещи.Я бы использовал последнее в этом случае, чтобы избежать смешивания: P –

+2

Дубликат: http://stackoverflow.com/questions/562129/how-do-i-use-moq-to-mock-an-extension-method. – Oliver

ответ

18

Вы не можете «непосредственно» измотать статический метод (следовательно, метод расширения) с насмешливой структурой. Вы можете попробовать Moles (http://research.microsoft.com/en-us/projects/pex/downloads.aspx), бесплатный инструмент от Microsoft, который реализует другой подход. Вот описание инструмента:

Моль представляет собой легкий каркас для тестирования заглушек и обходных путей в .NET, которая основана на делегатов.

Моли могут использоваться для обхода любого метода .NET, включая не виртуальные/статические методы в закрытых типах.

Вы можете использовать Moles с любой структурой тестирования (независимо от этого).

+2

Помимо Moles, существуют другие (несвободные) фальшивые фреймворки, которые используют API-интерфейс профилирования .NET для имитации объектов и поэтому могут заменять любые вызовы. Я знаю, что [JustMock] Telerik (http://www.telerik.com/products/mocking.aspx) и [TypeMock Isolator] (http://www.typemock.com/typemock-isolator-product3). –

+3

Родинки в теории хороши, но я обнаружил три проблемы, когда я пробовал это, что остановило меня, используя его ... 1) Он не работает в бегунке Resharper NUnit 2) Вам необходимо вручную создать сборку мола для каждой заглубленной сборки 3) Вам нужно вручную воссоздать сборку мола всякий раз, когда меняет шаблон. –

10

Я использовал обертку, чтобы обойти эту проблему. Создайте объект-обертку и передайте свой издеваемый метод.

См. Mocking Static Methods for Unit Testing от Пола Ирвина, у него есть хорошие примеры.

+0

Мне нравится этот ответ, потому что то, что он говорит (без прямого объяснения), вам нужно изменить свой код, чтобы он был доступен для проверки. Вот как это работает. Поймите, что в разработке микрочипов/IC/ASIC эти чипы должны быть не только предназначены для работы, но и еще более тщательно проверяемы, потому что, если вы не можете протестировать микрочип, это бесполезно - вы не можете гарантировать, что он будет Работа. То же самое касается программного обеспечения. Если вы не построили его для проверки, это ... бесполезно. Постройте его для проверки, что в некоторых случаях означает переписывание кода (и использование оберток), а затем создание автоматических тестов, которые его проверяют. –

1

Мне нравится использовать оболочку (шаблон адаптера), когда я обертываю сам объект. Я не уверен, что использую это для упаковки метода расширения, который не является частью объекта.

Я использую внутреннее Lazy Injectable Property любого типа Action, Func, Predicate или делегат и разрешаю вводить (заменяя) метод во время модульного теста.

internal Func<IMyObject, string, object> DoWorkMethod 
    { 
     [ExcludeFromCodeCoverage] 
     get { return _DoWorkMethod ?? (_DoWorkMethod = (obj, val) => { return obj.DoWork(val); }); } 
     set { _DoWorkMethod = value; } 
    } private Func<IMyObject, string, object> _DoWorkMethod; 

Затем вы вызываете Func вместо фактического метода.

public object SomeFunction() 
    { 
     var val = "doesn't matter for this example"; 
     return DoWorkMethod.Invoke(MyObjectProperty, val); 
    } 

Для более полного примера, проверьте http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/

+0

Это хорошо, но читатели должны знать, что _DoWorkMethod - это новое поле класса, которое каждый экземпляр класса теперь должен выделить еще одно поле. Редко это бывает, но иногда это происходит в зависимости от количества экземпляров, которые вы выделяете в любой момент времени. Вы можете обойти эту проблему, ставя статический _DoWorkMethod. Недостатком этого является то, что если у вас одновременно будут выполняться единичные тесты, завершатся два разных модульных теста, которые могут изменять одно и то же статическое значение. – zumalifeguard

3

я обнаружил, что я должен был обнаружить внутри метода расширения Я пытался издеваться вход для, и насмешка, что происходит внутри расширение.

Я рассматривал, как расширения являются статическими, что походит на то, что вы вводите код непосредственно в свой метод, поэтому вам нужно издеваться над тем, что происходит внутри расширения, а не с самим расширением.

Смежные вопросы