我刚刚开始使用MSpec(使用James Broome的AutoMocking)和RhinoMocks进行BDD / TDD。这是我的练习项目的摘录:
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);
}
如您所见,我在MovieRepository类上删除了FindMovies()方法。然后我正在调用MoviesController.Find()动作。我的问题是,是否应该有一个断言来检查控制器是否调用了stubbed方法(FindMovies)?或者也许我应该只关心返回的结果而不是它取自何处?此外,一个说“should_fetch_movies_from_the_repository”的规范看起来很像工程任务,而不是客户可能理解的东西 - 它是否在BDD中占有一席之地?
答案 0 :(得分:1)
断言的一般规则是断言输出交互,而不是输入交互。
FindMovies存根将“电影”集合返回给调用它的类,然后您通过“它应该返回与导演匹配的电影列表”断言验证该类是否收到了正确的列表。如果FindMovies方法不被调用,则此断言将失败。
因此,您不需要对FindMovies方法断言。
要反驳这一点,如果你有一个纯输出的模拟或存根 - 让我们说一个由Presenter类调用的IView接口,那么你确实想要对被调用的IView断言。例如,这段代码:
public class MyPresenter
{
... other code here
public DoSomething()
{
IList data = GetSomeData();
myView.DisplayData(data);
}
}
你想断言在这种情况下调用了view.DisplayData方法,因为你没有从这个调用中检索任何可以被另一个测试声明的东西。
至于“从存储库中获取” - 当然,您的客户关心这一点。他们希望系统将电影保存到存储中并从存储中加载它们。但是... FindMovies调用是被测试类的输入,因此根本没有必要进行这种调用或测试。如果未调用FindMovies方法,则另一个测试将失败并让您知道存在问题。