У меня есть типичное приложение Silverlight со службой WCF, и я использую slsvcutil.exe для создания стандартного клиентского прокси-сервера для связи с веб-службой.Я пытаюсь написать модульные тесты и пытаюсь использовать инфраструктуру модульного тестирования Silverlight и Moq для макетирования прокси-сервера и удаления зависимости службы для тестирования.
Я очень плохо знаком с Moq и у меня многопроблема с автоматическим вызовом различных событий Completed на смоделированном прокси-сервере автоматически, когда выполняются сервисные вызовы для имитации асинхронных вызовов.
Для того, чтобы сделать прокси-сервер "поддельным", я создал свой собственныйпростой интерфейс для сгенерированных прокси-вызовов и их завершенных событий:
public interface IServiceProxy
{
void TestAsync(TestRequest request);
void TestAsync(TestRequest request, object userState);
event EventHandler<TestCompletedEventArgs> TestCompleted;
}
Я также подклассифицировал сгенерированный прокси-объект для реализации этого интерфейса:
public class MyServiceProxy : GeneratedServiceClient, IServiceProxy, ICommunicationObject
{
// ... overloaded proxy constructors
}
После просмотра документации Moq, этоВот как я пытаюсь настроить макет, чтобы ожидать вызова TestAsync () и немедленно вызвать событие TestCompleted с результатом в EventArgs:
[TestMethod]
public void Test_Returns_Expected()
{
var mockProxy = new Mock<IServiceProxy>();
var result = new TestResponse() { Value = true };
this.mockProxy.Setup(
p => p.TestAsync(It.IsAny<TestRequest>()))
.Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, null));
// rest of the test to actually use the mock and assert things
}
Все прекрасно, но когда я пытаюсь запустить любойвид проверки с использованием макета и установки точек останова, событие TestCompleted никогда невозникает, когда я вызываю TestAsync ().
Есть ли что-то очевидное, чего мне не хватает, или есть какие-нибудь идеи о том, чтобы высмеивать эти типы прокси-серверов асинхронных служб в Silverlight?
Спасибо!
РЕДАКТИРОВАТЬ:
Чтобы было более понятно, что я на самом деле пытаюсь протестировать, это вспомогательный класс, который я создал, который использует экземпляр IServiceProxy
и предоставляет более чистый интерфейс сервиса для моей ViewModel, который можно использовать, принимая параметры обратного вызова Action<TResponse, Exception>
вместо того, чтобы иметь дело с событиями обратного вызова в моей ViewModel.Я понимаю, как это можно смоделировать, чтобы напрямую протестировать мою ViewModel, но я решил, что было бы неплохо сначала протестировать класс помощника.
Вот пример того, о чем я говорю:
public class HelperClient : IServiceHelper
{
private IServiceProxy proxy;
public HelperClient(IServiceProxy proxy)
{
this.proxy = proxy;
// register to handle all async callback events
this.proxy.TestCompleted += new EventHandler<TestCompletedEventArgs>(TestCompleted);
}
public void Test(TestRequest request, Action<TestResponse, Exception> response)
{
this.proxy.TestAsync(request, response);
}
private void TestCompleted(object sender, TestCompletedEventArgs e)
{
var response = e.UserState as Action<TestResponse, Exception>;
if (response != null)
{
var ex = GetServiceException(e);
if (ex == null)
{
response(e.Result, null);
}
else
{
response(null, ex);
}
}
}
}
Итак, в моем тесте я на самом деле проверяю ISerivceProxy и передаю его, а также просто пытаюсь проверить вызов службы, чтобы убедиться, что оболочка правильно вызывает Action:
[TestMethod]
[Asynchronous]
public void Test_Returns_Expected()
{
var mockProxy = new Mock<IServiceProxy>();
var helper = new HelperClient(mockProxy.Object);
bool expectedResult = true;
var result = new TestResponse() { Value = expectedResult };
this.mockProxy.Setup(
p => p.TestAsync(It.IsAny<TestRequest>()))
.Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, null));
helper.Test(new TestRequest(), (response, ex) =>
{
Assert.AreEqual(expectedResult, response.Value);
EnqueueTestComplete();
});
}
Проблема заключается в том, что макет прокси-объекта никогда не вызывает событие TestCompleted, поэтому мое ответное действие никогда не вызывается для завершения теста (даже при том, что тест, кажется, завершается успешно, Assert фактически никогда не запускается).Извините за такой длинный пост, просто пытаюсь показать вам как можно больше кода.
РЕДАКТИРОВАТЬ 2
Добавлен [Asynchronous]
и вызов EnqueueTestComplete()
, который японял, что мне может понадобиться подождать, пока событие не будет вызвано.Это не очень помогло, событие до сих пор никогда не вызывается, поэтому тест просто зависает и никогда не завершается.
РЕДАКТИРОВАТЬ 3
Ответ Алиостада был верным, что подпись моего ожидания установки была правильнойне соответствует действительной сигнатуре Test (), что позволяет мне передать ответное действие в качестве второго параметра.Глупая ошибка, но именно это мешало Moq вызвать событие Completed.Я также забыл передать Action как объект userState в TestCompletedEventArgs, чтобы он действительно вызывался при возникновении события Completed.Кроме того, [Asynchronous]
и EnqueueTestCompleted
в этом случае, по-видимому, не нужны.
Вот обновленный тестовый код для всех, кто интересуется:
[TestMethod]
public void Test_Returns_Expected()
{
var mockProxy = new Mock<IServiceProxy>();
var helper = new HelperClient(mockProxy.Object);
bool expectedResult = true;
var result = new TestResponse() { Value = expectedResult };
Action<TestResponse, Exception> responseAction = (response, ex) =>
{
Assert.AreEqual(expectedResult, response.Value);
};
this.mockProxy.Setup(
p => p.TestAsync(It.IsAny<TestRequest>(), It.IsAny<Action<TestResponse, Exception>>()))
.Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, responseAction));
helper.Test(new TestRequest(), responseAction);
}