2013-11-27 3 views
1

У меня есть класс похож на это:Утверждение пустоты асинхронного метода

public class MyClass 
{ 
    public Task MyMethod() 
    { 
     //do something 
    } 
} 

Как описано выше, «MyMethod» является асинхронным, позволяет сказать, для простоты, что это его реализация:

public Task MyMethod() 
    { 
     return Task.Run(() => 
     { 
      var success = _someService.DoSomething(); 
      if (!success) throw new Exception("unsuccsesfull"); 
     }); 

    } 

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

Я хочу протестировать этот метод. Метод испытания будет выглядеть так:

[Test] 
public async void TestMyMethod_TestInitialState_TestExpectedResult() 
{ 
    // test initialization.. 
    //... 
    //.. 
    var myClass = new MyClass(); 
    await myClass.MyMethod(); 

    Assert.That(????) 
} 

Мой вопрос - какое правильное утверждение?

У меня есть возможное решение - добавить логический элемент в «MyClass» и обновить этот элемент в соответствии с результатом метода:

public class MyClass 
{ 
    public bool SomeMember { get; private set; } 

    public Task MyMethod() 
    { 
     Task.Run(() => 
     {    
      SomeMember = _someService.DoSomething(); 
      if (!SomeMember) throw new Exception("unsuccsesfull"); 
     }); 

    } 
} 

Таким образом, я могу утверждать, тест вроде этого:

[Test] 
    public async void TestMyMethod_TestInitialState_SomeMemberShouldBeTrue() 
    { 
     // test initialization.. 
     //... 
     //.. 
     var myClass = new MyClass(); 
     await myClass.MyMethod(); 

     Assert.True(SomeMember) 
    } 
} 

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

Предложения?

Парень.

+0

Ну предположительно асинхронная операция имеет некоторый эффект - в противном случае было бы бессмысленно его выполнения. Что он делает, и вы можете проверить, что это произошло? –

+0

В моем случае он отправляет файл другому компьютеру. Это делается путем обхода сообщений связи и включения сервера TFTP, с которого другая машина запрашивает файл. Я узнаю об успешности этого процесса с помощью коммуникационного сообщения, которое я получу от этой машины, указывающей на то, что файл находится в его потере. Я не контролирую, когда это сообщение будет отправлено, следовательно, асинхронный интерфейс я exspoing –

+0

Итак, что он делает в вашей тестовой ситуации? Предположительно, на самом деле это не делает TFTP в этом случае ... –

ответ

3

Вам нужен так называемый «макет» или «заглушка». Идея состоит в том, что вы реорганизуете свой код так, чтобы он зависел от интерфейса, а затем вы издеваетесь над интерфейсом во время тестирования.

Существуют различные рамки/инструменты, которые помогают в издевательстве (Moq, Microsoft Fakes, TypeMock Isolator, JustMock и т. Д.), А также существует множество фреймворков, которые помогают с близкой проблемой инъекции зависимостей (Unity, Castle Windsor, StructureMap, Autofac и т. Д.).

Но вы можете начать делать это самостоятельно. Во-первых, рефакторинг MyClass так это зависит от ISomeService:

public interface ISomeService 
{ 
    bool DoSomething(); 
} 

public class MyClass 
{ 
    private readonly ISomeService _someService; 

    public MyClass(ISomeService someService) 
    { 
    _someService = someService; 
    } 

    public Task MyMethod() 
    { 
    return Task.Run(() => 
    { 
     var success = _someService.DoSomething(); 
     if (!success) throw new Exception("unsuccsesfull"); 
    }); 
    } 
} 

Затем в тестовом модуле:

private class TestService : ISomeService 
{ 
    public bool DoSomethingReturnValue { get; set; } 

    public bool DoSomething() { return DoSomethingReturnValue; } 
} 

[Test] 
public async Task TestMyMethod_TestInitialState_TestExpectedResult() 
{ 
    var myClass = new MyClass(new TestService { DoSomethingReturnValue = true }); 
    await myClass.MyMethod(); 
} 

[Test] 
public async Task TestMyMethod_TestInitialState_TestFailure() 
{ 
    var myClass = new MyClass(new TestService { DoSomethingReturnValue = false }); 
    Assert.Throws(() => myClass.MyMethod()); // (I'm unsure of the exact NUnit syntax) 
} 
+0

althoug Я не спрашивал насчет насмешек Я думаю, что ваш ответ соответствует моим требованиям ... спасибо! –

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