Мультиинтерфейсы Moq

Предыстория:

Я создал простую прокси для моего Wcf-клиента, основанную частично на примерах, найденных в Интернете, и частично на моих потребностях.

Использование для создания клиентского прокси, как известно:

WcfClientProxy<IServicecontract> clientProxy = 
                                 new WcfClientProxy<IServiceContract>();

WcfClientProxy имеет метод Execute, который принимает: Expression<Func<TChannel, TResult>> или Expression<Action<TChannel>>.

Чего я пытаюсь достичь:

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

Так издеваться над таким звонком ..

clientProxy.Execute(m=>m.DoSomeAction(5));

Проблема:

Проблема в том, что мокап не работает. Я получаю эту ошибку:

"выбросил исключение: System.NullReferenceException: ссылка на объект не указывает на экземпляр объекта".

Мой контракт на тестовое обслуживание:

public interface ITestingServiceInterface : System.ServiceModel.IClientChannel
{
    string Version();
    VersionDetail VersionDetail();
    IList<VersionDetail> VersionDetails();
    void DoSomeDelete(int itemId);
}

Интерфейс прокси клиента wcf:

public interface IWcfClientProxy<TChannel> where TChannel : ICommunicationObject
{
    bool ThrowOnException { get; set; }
    TResult Execute<TResult>(Expression<Func<TChannel, TResult>> operation);
    void Execute(Expression<Action<TChannel>> expression);
}

Моя попытка теста и макета с настройкой..

private List<ProdItem> items;
private Mock<IWcfClientProxy<ITestingServiceInterface>> mockClientProxy;

[TestInitialize]
public void SettingUp()
{
    mockClientProxy = new Mock<IWcfClientProxy<ITestingServiceInterface>>();

    items = new List<ProdItem>();
    for( int i =0; i<10; i++){
        items.Add(new ProdItem { ProdItemId = i, LocalStock = i });
    }
}

[TestMethod]
public void SimpleTest()
{
    mockClientProxy.Setup(m => m.Execute(x => x.DoSomeDelete(It.IsAny<int>()))).Callback(RemoveItem);

    var client = mockClientProxy.Object;

    client.Execute(x => x.DoSomeDelete(4));

    Assert.AreEqual(9, items.Count);
}

public void RemoveItem()
{
    items.RemoveAt(items.Count - 1);
}

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

Я уверен, что только что сделал что-то глупое.

Обновление: показан пример того, что я хотел бы проверить, работает ли вышеперечисленное..

[TestMethod]
public void SimpleTest()
{
    mockClientProxy.Setup(m => m.Execute(x => x.DoSomeDelete(It.IsAny<int>()))).Callback(RemoveItem);

    var client = mockClientProxy.Object;

    var stockHelper = new StockHelper(client);

    stockHelper.DeleteItem(5);

    Assert.AreEqual(9, items.Count);
}

В приведенном выше примере я тестирую класс StockHelper, который использует клиентский прокси в своем конструкторе, через который он выполняет вызовы WCF.

Чтобы протестировать StockHelper (или что-то еще), мне нужно иметь возможность издеваться над клиентом и его служебными вызовами. Вышеупомянутый (1-й) пример указывает на то, что у меня возникла проблема с попыткой сделать это.

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


person David McLean    schedule 02.04.2012    source источник


Ответы (2)


Как я вижу из вашего кода, вы тестируете mock. Я не вижу никакого реального объекта, который вы тестируете. Макеты используются для заглушки зависимостей тестируемых объектов. Итак, если какой-то класс Foo использует IWcfClientProxy, вы предоставляете макет этого прокси для класса Foo. И убедитесь, что во время Foo.Bar() выполнения был вызван метод DoSomeDelete зависимости. Это цель моков.

[TestClass]
public class FooTests
{
   private Foo _foo;
   private Mock<IWcfClientProxy<ITestingServiceInterface>> _clientProxy;

   [TestInitialize]
   public void SettingUp()
   {
       _clientProxy = new Mock<IWcfClientProxy<ITestingServiceInterface>>();
       _foo = new Foo(_clientProxy.Object);
   }

   [TestMethod]
   public void SimpleTest()
   {
       // Act on object being tested
       _foo.Bar(5);

       // verify it executed correct method on dependency
       _clientProxy.Verify(cp => cp.Execute(x => x.DoSomeDelete(5)));
    }
}

Имейте в виду, что при тестировании Foo вас не должно волновать, как реализован _clientProxy.

person Sergey Berezovskiy    schedule 02.04.2012
comment
Клиентский прокси обычно передается чему-то, скажем, вспомогательному классу. тогда тесты будут тестировать вспомогательный класс, а не прокси, но, поскольку я не могу проверить прокси в данный момент, я не показывал это в качестве примера. Если я не передаю никаких параметров методу службы, он работает так, как ожидалось. - person David McLean; 02.04.2012
comment
Я обновил вопрос (только что увидел ваш обновленный ответ). Нужно ли мне использовать проверку, а не настраивать возвраты и обратные вызовы? это будет моя проблема? - person David McLean; 02.04.2012
comment
Прокси имеет метод Execute. Поэтому вам нужно убедиться, что этот метод был вызван с правильными параметрами. При необходимости вы можете предоставить какое-то поддельное возвращаемое значение для издевательства над методом. (извините время обеда, вернусь через час) :) - person Sergey Berezovskiy; 02.04.2012
comment
Пробовал, жалуется, что метод никогда не вызывается. - person David McLean; 02.04.2012
comment
Если вы хотите установить какое-либо действие в качестве параметра Execute, используйте _clientProxy.Setup(cp => cp.Execute(It.IsAny<Expression<Action<ITestingServiceInterface>>>()))//.Callback() - person Sergey Berezovskiy; 02.04.2012
comment
Кстати, если вы хотите проверить точное совпадение параметра выражения, я не думаю, что это возможно с moq: groups.google.com/group/moqdisc/browse_thread/thread/ - person Sergey Berezovskiy; 02.04.2012
comment
Проблема как-то связана с приведенной выше ссылкой. Это означает, что я не могу издеваться над отдельными вызовами методов из моего сервиса. Что немного обидно, так как мне может понадобиться для классов, которые вызывают пару служебных методов для данных, прежде чем выполнять работу с этими данными. Если это имеет смысл. Неважно, спасибо за вашу помощь. - person David McLean; 02.04.2012

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

mockClientProxy.Setup(m => m.Execute(It.IsAny<Expression<Action<TChannel>>>())).Callback(RemoveItem);

Moq работает, реализуя методы интерфейса своего аргумента, в данном случае это методы интерфейса IWcfClientProxy<ITestingServiceInterface>. Поэтому, когда вы настраиваете вызов метода Execute, вам необходимо настроить соответствующие параметры для аргументов Execute. Что вы сделали в своем коде, так это настроили соответствие для этой конкретной функции делегата, которая на самом деле никогда не будет соответствовать чему-либо, потому что вы не сохраняете ее и не вызываете Execute с ней позже.

person Erik    schedule 26.01.2015