2010-02-25 5 views
0

Я только начинаю с BDD/TDD, используя MSpec (с AutoMocking Джеймсом Брумом) и RhinoMocks. Вот отрывок из моей практики проекта:Должен ли я проверить, был ли вызван метод stubbed?

namespace Tests.VideoStore.Controllers 
{ 
    public abstract class context_for_movie_controller : 
    Specification<MovieController> 
    { 
     private static IList<Movie> movies; 
     protected static IMovieRepository _movieRepository; 
     protected static ActionResult _result; 
     protected static string title; 
     protected static string director; 

     Establish context =() => 
     { 
      _movieRepository = DependencyOf<IMovieRepository>(); 
     }; 
    } 

    [Subject(typeof(MovieController))] 
    public class when_searching_for_movies_with_director : 
    context_for_movie_controller 
    { 
     Establish context =() => 
     { 
      title = null; 
      director = "James Cameron"; 

      var movie4 = new Movie { 
       Title = "Terminator", Director = "James Cameron"}; 
      var movie6 = new Movie { 
       Title = "Avatar", Director = "James Cameron"}; 

      movies = new List<Movie> {movie4, movie6}; 

      // Repository returns all movies. 
      _movieRepository.Stub(x => x.FindMovies(title, director)) 
      .Return(movies); 
     }; 

     Because of =() => _result = subject.Find(title, director); 

     It should_fetch_movies_from_the_repository =() => 
      _movieRepository.AssertWasCalled(x => 
       x.FindMovies(title, director)); 

     It should_return_a_list_of_movies_matching_the_director =() => 
      _result.ShouldBeAView().And() 
      .ShouldHaveModelOfType<IEnumerable<Movie>>) 
      .And().ShouldContainOnly(movies); 
    } 

Как вы можете видеть, я погасил FindMovies() метод на MovieRepository класса. Затем я вызываю действие MoviesController.Find(). Мой вопрос в том, должен ли быть утвердитель, чтобы проверить, был ли вызванный метод (FindMovies) вызванным контроллером? Или, может быть, я должен заботиться только о возвращенном результате, а не о том, откуда он был взят? Кроме того, спецификация, которая говорит «should_fetch_movies_from_the_repository», очень похожа на инженерную задачу, а не на то, что может понять клиент, - имеет ли она свое место в BDD?

ответ

1

Общее правило для утверждения утверждений состоит в том, что вы утверждаете против взаимодействия вывода, а не с входными взаимодействиями.

Запуск FindMovies возвращает коллекцию «фильмов» классу, который ее назвал, и затем вы проверяете, что класс получил правильный список через «он должен вернуть список фильмов, соответствующих утверждению директора». если метод FindMovies имеет значение , а не, то это утверждение не будет выполнено.

поэтому вам не нужно утверждать вызовы метода FindMovies.

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


public class MyPresenter 
{ 
    ... other code here 

    public DoSomething() 
    { 
    IList data = GetSomeData(); 
    myView.DisplayData(data); 

    } 
} 

вы хотели бы утверждать, что метод view.DisplayData называется в этом случае, потому что вы ничего из этого вызова, который может быть предъявлен другой тест не загружается.

как для «извлечения из хранилища» - конечно, ваши клиенты заботятся об этом. они хотят, чтобы система сохраняла фильмы в хранилище и загружала их из хранилища. однако ... вызов FindMovies представляет собой вход в тестируемый класс, поэтому нет необходимости иметь это преимущество или тест вообще. если метод FindMovies не вызывается, тогда другой тест завершится ошибкой и сообщит вам, что есть проблема.

+0

Правильно, теперь я вижу, что тест потерпит неудачу, если я не использовал FindMovies в действии контроллера. Однако, если я каким-то образом создал один и тот же список различными способами, чем вызов FindMovies, тест пройдет. Наверное, мне все равно, где данные поступают, если это действительно так, верно? –

+1

вы делаете, и вы не заботитесь. вы заботитесь о том, чтобы данные были загружены из внешнего механизма хранения, но вам все равно, как он был загружен из этого механизма хранения. реальная выгода заключается в том, что вы не создаете хрупкие тесты, которые начинают сбой при изменении вашего API или реализации. если вы решили заменить свой вызов на FindMovies с помощью механизма кэширования, который, например, имел метод «FindMoviesInCache», ваш тест все равно будет проходить до тех пор, пока заглушенный FindMoviesInCache вернет правильные данные. –