2016-12-17 19 views
0

如何为排序函数(使用Comparator)编写单元测试,当排序的对象是模拟对象时?由比较器(EasyMock)嘲笑排序的列表

只是一个小例子:我有一个电影的Libary。三类:库,电影,myCmpMovies(实现比较器)。 我正在测试将它隔离的类库。对于这个目标,我正在嘲笑类Movie,以测试Library中的所有方法。

使用EasyMock。

我排序的电影列表中这样说:

class Library{ 
    ArrayList<Movie> movies; 
    public List<Movie> getSortedMoviesByDatesAndNames() { 
     List<Movie> movies = this.getMovies(); 
     Comparator myCmpMovies = new myCmpMovies(); 
     Collections.sort(movies, myCmpMovies); 
     return movies; 
    } 
} 

现在,我正在测试这种方法用一个单元测试。模拟对象是电影。我只是想尝试像这样:

@Test 
    public List<Movie> TestGetSortedMoviesByDatesAndNames() { 
     movie1= createMock(Movie.class); 
     movie2= createMock(Movie.class); 
     movie3= createMock(Movie.class); 

     .... 
    } 

我知道这个主题有几个问题,但我认为这些不是同一个问题。

在此先感谢。

回答

3

您的评论部分编辑:如果你真的要坚持与“笨拙的”电影类的,你想要去的嘲讽,我会做它在某种程度上是这样的:

Movie mockMovieWith(String title, Date releaseDate, ...) { 
    Movie mockedMovie = createMock(Movie.class); 
    expect(mockedMovie.getTitle()).andStubReturn(title); 
    expect(mockedMovie.getReleaseDate())... 
    replay(mockedMovie); 
    return mockedMovie; 
} 

换句话说:使用助手方法来创建一个模拟的Movie对象,该对象具有您认为应该/将被稍后使用模拟对象的“真实”代码使用的那些属性。

但如下所述;你真的应该在这里添加一些“反腐败层”。意思是:当这个“外部”库Movie类很难使用,然后包装一些东西 - 这样你的代码就不会被该Movie类中的糟糕设计所破坏!

......并且为了记录,这里是最初的答案。

你在许多层面上都出现这种错误。首先,你是shadowing你的字段电影在你的方法中有一个局部变量。这很少是一个好主意,因为它会导致各种微妙的错误。

然后:首先要测试的不是那种方法;它本身就是比较器。含义:你依靠Collections.sort();没有必要测试的一部分。你想确保你的比较器做它应该做的事情。

从这个意义上说,你的第一个测试用例应该简单地定义两个Movie对象;然后调用比较器的compareTo方法并检查预期的结果。

导致你的问题的真正主题:你应该不是需要模拟电影对象。这些东西代表某种数据。从这个意义上说:你不要实例化模拟数据,你只需创建具有已知内容的真实Movie对象。

例如,假设一个电影的核心属性是它的标题,你去像:

Movie movieA = new Movie("Title A"); 
Movie movieB = new Movie("Title B"); 

这就是你会喂到你比较什么。或者,也许进入你的电影列表(你仍然想做至少一个“集成”测试,以确保getSortedMovies ...()做它应该做的)。

如果你认为你需要模拟电影对象,比你有一个糟糕的设计。这很简单。如果它不像上面那样容易实例化一个Movie对象,那么你应该启用它。

因为否则的话你必须做一些事情,如:

Movie mockedMovieA = createMock(Movie.class); 

之后提供的所有特性模拟预计,如:

expect(mockedMovieA.getTitle()).andReturn("Title A"); 

这将是非常繁琐,容易出错。

所以,如上所述,核心你应该看看的东西:创建一个设计,允许你在单元测试中使用“真正的”电影对象。如果你的电影类包含很多东西,这是不可能的...比这是一个明确的迹象,你的电影类太大了,做不属于它的东西。

解决这些“太大”问题的第一种方法是:可以将包含当前Movie类核心方法(如getTitle(),getReleaseDate())的“Movie”接口分开。然后全部你的代码只适用于那个接口......这可能很容易被嘲弄;或者由一个更“愚蠢的”测试类来实现。

+0

感谢您的快速回复!我忘了说我正在测试课堂图书馆将它隔离起来。对于这个目标,我正在嘲笑类Movie,以测试Library中的所有方法。在这种情况下,现在出现了测试排序方法的问题。所以,也许我将不得不尝试你最后的提示,并介绍和接口。 – mikiasda

+0

我提出了一些更新,也许他们对你有帮助。如果是这样,请考虑在某个时候接受;;我不认为其他答案会以你的方式出现。 – GhostCat

+0

非常感谢!这些关键技巧帮助了我! – mikiasda

0

如何为排序函数(使用Comparator)编写单元测试,当排序的对象是模拟对象时?

With UnitTest you test the observable behavior

这意味着您检查返回的集合中的对象是否具有正确的顺序,而不管该方法如何实现该顺序。

@Test 
    public void TestGetSortedMoviesByDates() { 
     movie1= createMock(Movie.class); 
     movie2= createMock(Movie.class); 
     movie3= createMock(Movie.class); 

     expect(movie1.getName()).andReturn("any name"); 
     expect(movie2.getName()).andReturn("any name"); 
     expect(movie3.getName()).andReturn("any name"); 

     Date date = new Date(); // curent Date 
     expect(movie2.getDate()).andReturn(date.clone()) 
     date.setYear(date.getYear()+1); 
     expect(movie3.getDate()).andReturn(date.clone()) 
     date.setYear(date.getYear()+1); 
     expect(movie1.getDate()).andReturn(date.clone()) 

     List<Movie> movies = Arrays.asList(movie1,movie2,movie3); 
     Library library = new Library(); 
     // put the list into the library 
     List<Movie> sortedMovies = library.getSortedMoviesByDatesAndNames(); 

     assertArrayEquals(sortedMovies, Arrays.asList(movie2,movie3,movie1)); 
    } 

    @Test 
    public void TestGetSortedMoviesByNamesForEqualDates() { 
     movie1= createMock(Movie.class); 
     movie2= createMock(Movie.class); 
     movie3= createMock(Movie.class); 

     expect(movie1.getName()).andReturn("ZZ Last after sort"); 
     expect(movie2.getName()).andReturn("AA first after sort"); 
     expect(movie3.getName()).andReturn("MM middle after sort"); 

     Date date = new Date(); // curent Date 
     expect(movie2.getDate()).andReturn(date) 
     expect(movie3.getDate()).andReturn(date) 
     expect(movie1.getDate()).andReturn(date) 

     List<Movie> movies = Arrays.asList(movie1,movie2,movie3); 
     Library library = new Library(); 
     // put the list into the library 
     List<Movie> sortedMovies = library.getSortedMoviesByDatesAndNames(); 

     assertArrayEquals(sortedMovies, Arrays.asList(movie2,movie3,movie1)); 
    } 
+0

非常感谢!这非常有用! – mikiasda