Трябва ли да тествам дали е извикан метод за заглушаване?

Тъкмо започвам с BDD/TDD, използвайки MSpec (с AutoMocking от James Broome) и RhinoMocks. Ето откъс от моя практически проект:

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(). Въпросът ми е трябва ли да има assert, за да се провери дали методът stubbed (FindMovies) е извикан от контролера? Или може би трябва да ме интересува само върнатият резултат, а не откъде е взет? Освен това спецификация, която казва „should_fetch_movies_from_the_repository“, изглежда много като инженерна задача, а не нещо, което клиентът може да разбере – има ли мястото си в BDD?


person Pawel Krakowiak    schedule 25.02.2010    source източник


Отговори (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 не бъде извикан, тогава другият тест ще се провали и ще ви уведоми, че има проблем.

person Derick Bailey    schedule 25.02.2010
comment
Добре, сега виждам, че тестът ще се провали, ако не използвам FindMovies в действието на контролера. Въпреки това, ако по някакъв начин създам същия списък по начин, различен от извикването на FindMovies, тестът ще премине. Предполагам, че не трябва да ме интересува откъде идват данните, стига да са валидни, нали? - person Pawel Krakowiak; 26.02.2010
comment
правите и не ви пука. грижите се, че данните са били заредени от външен механизъм за съхранение - но всъщност не ви интересува как са били заредени от този механизъм за съхранение. истинската полза е, че не създавате крехки тестове, които започват да се провалят, когато промените своя API или внедряване. ако сте решили да замените извикването си към FindMovies с механизъм за кеширане, който има метод, наречен FindMoviesInCache например, вашият тест ще продължи да преминава, докато закъсаният FindMoviesInCache връща правилните данни. - person Derick Bailey; 26.02.2010