2014-09-03 2 views
2

Рассмотрим следующий тест единицы измерения:Когда я должен утверждать действия SUT?

[Test] 
public void Success() 
{ 
    var userID = 5; 
    var user = new User(); 
    var dataAccess = new Mock<IDataAccess>(); 
    dataAccess.Setup(x => x.GetUser(userID)).Returns(user).Verifiable(); 
    var sut = new UserController(dataAccess.Object); 

    var returnedUser = sut.GetUser(userID); 

    Assert.AreSame(user, returnedUser); 
    dataAccess.Verify(x => x.GetUser(userID), Times.Once()); 
} 

Последние чтение предположил, что я должен использовать только макет, чтобы предоставить пользователю и должен быть один утверждают (AreSame один). По-видимому, идеальный модульный тест не должен беспокоиться о проверке поведения сут.

Больше как это:

[Test] 
public void Success() 
{ 
    var userID = 5; 
    var user = new User(); 
    var dataAccess = new Mock<IDataAccess>(); 
    dataAccess.Setup(x => x.GetUser(userID)).Returns(user); 
    var sut = new UserController(dataAccess.Object); 

    var returnedUser = sut.GetUser(userID); 

    Assert.AreSame(user, returnedUser); 
} 

Это упрощенный тест лучше? Должны ли Unit Tests утверждать поведение методов, которые они называют, или только результаты?

+1

возможно дубликат [государственного тестирования/взаимодействия и путаницы при смешении (или злоупотребление) их] (http://stackoverflow.com/questions/1300221/state-interaction-testing-and -confusion-on-mix-or-abusing-them) –

+1

И это хорошая справочная статья: http://martinfowler.com/articles/mocksArentStubs.html –

ответ

2

Одна основная идея состоит в том, чтобы иметь только один тест в тесте. Поэтому, возможно, вам стоит рассмотреть два теста. Важным является первый тест на основе стоимости. Второй тест на взаимодействие, вероятно, не подходит в этом случае. По словам Роя Ошерова: «Вы используете тестирование взаимодействия при вызове другого объекта - это конечный результат конкретной единицы работы».

Пример:

namespace Tests 
{ 
    [TestClass] 
    public class UserControllerTest 
    { 
     [TestMethod] 
     public void GetUser_WhenCalled_ReturnsUserSameAsDataAccess() 
     { 
      // Arrange 
      const int userID = 5; 
      User expectedUser = new User(); 

      Mock<IDataAccess> dataAccessStub = new Mock<IDataAccess>(); 
      dataAccessStub.Setup(x => x.GetUser(userID)).Returns(expectedUser); 
      UserController controller = new UserController(dataAccessStub.Object); 

      // Act 
      User actualUser = controller.GetUser(userID); 

      // Assert 
      Assert.AreSame(expectedUser, actualUser); 
     } 

     [TestMethod] 
     public void GetUser_WhenCalled_GetUserOnDataAccessIsCalledOnce() 
     { 
      // Arrange 
      const int userID = 5; 
      const int getUserCallsCountExpected = 1; 
      int getUserCallsCount = 0; 

      Mock<IDataAccess> dataAccessMock = new Mock<IDataAccess>(); 
      dataAccessMock.Setup(x => x.GetUser(userID)).Callback(() => getUserCallsCount++); 
      UserController controller = new UserController(dataAccessMock.Object); 

      // Act 
      controller.GetUser(userID); 

      // Assert 
      Assert.AreEqual(getUserCallsCountExpected, getUserCallsCount); 
     } 
    } 
} 
+0

Я согласен с первым тестом. Но я всегда стараюсь оценить, какое значение добавляет второй тест? Разве это не проверка внутренней реализации API? Будет ли этот тест устойчивым к рефакторингу? Не следует ли проходить единичный тест до тех пор, пока общественное поведение не изменится? – Amol

+0

@ Амол да, я думаю, что вы правы, второй тест, вероятно, не подходит в этом случае. Я отредактировал ответ. – dee

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