tags:

views:

40

answers:

1

I'm just starting out with BDD/TDD using MSpec (with AutoMocking by James Broome) and RhinoMocks. Here's an excerpt from my practice project:

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);
    }

As you can see, I stubbed out the FindMovies() method on the MovieRepository class. Then I'm calling the MoviesController.Find() action. My question is, should there be an assert to check if the stubbed method (FindMovies) was called by the controller? Or perhaps should I only care about the returned result and not where it was taken from? Furthermore, a spec that says "should_fetch_movies_from_the_repository" looks a lot like an engineering task, not something that a client might understand - does it have its place in BDD?

+1  A: 

the general rule to follow for assertions is that you assert against output interactions, not input interactions.

the FindMovies stub is returning a "movies" collection to the class that called it and you are then verifying that the class received the correct list via the "it should return a list of movies matching the director" assertion. if the FindMovies method is not called, then this assertion will fail.

therefore, you do not need to assert the calls against the FindMovies method.

to counterpoint this, if you have an mock or stub that is purely output - let's say an IView interface being called by a Presenter class, then you do want to assert against the IView being called. for example, this code:


public class MyPresenter
{
  ... other code here

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

  }
}

you would want to assert that the view.DisplayData method is called in this case, because you are not retrieving anything from this call that can be asserted by another test.

as for the "fetch from repository" - of course your customers care about that. they want the system to save movies to the storage and load them from the storage. however ... the FindMovies call is an input into the class being tested, so it's not necessary to have this assetion or test, at all. if the FindMovies method is not called, then the other test will fail and let you know that there is a problem.

Derick Bailey
Right, now I see that the test would fail if I did not use FindMovies in the controller action. However if I somehow created the same list by different means than calling FindMovies, the test would pass. I guess I should not care about where the data comes from, as long as it's valid, right?
Pawel Krakowiak
you do and you dont care. you care that the data was loaded from an external storage mechanism - but you don't really care how it was loaded from that storage mechanism. the real benefit is that you are not creating brittle tests that begin to fail when you change your API or implementation. if you decided to replace your call to FindMovies with a caching mechanism that had a method called "FindMoviesInCache" for example, your test would still pass as long as the stubbed FindMoviesInCache returns the right data.
Derick Bailey