比较器模拟排序列表(EasyMock)

时间:2016-12-17 12:15:34

标签: java unit-testing easymock

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

只是一个小例子:我有一个带电影的图书馆。三个类:Library,Movie,myCmpMovies(实现Comparator)。 我正在测试它隔离的类库。对于这个目标,我正在模拟类Movie,以测试库中的所有方法。

使用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);

        ....
    }

我知道有关于这个主题的一些问题,但我认为这些问题不同。

提前致谢。

2 个答案:

答案 0 :(得分:3)

对你的评论进行了一些编辑:如果你真的必须坚持这个&#34;笨拙&#34;电影课,你想去嘲笑,我会这样做:

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

换句话说:使用辅助方法创建一个模拟的Movie对象,该对象具有您认为应该/将要使用的&#34; real&#34;稍后将使用模拟对象的代码。

但如下所示;你真的应该添加一些&#34;反腐败层&#34;这里。含义:当&#34;外部&#34;库电影类很难使用,然后包装一些东西 - 这样你的代码就不会被那个Movie类中糟糕的设计所破坏!

...而且对于记录,这是最初的答案。

你在很多层面都犯了这个错误。首先,您在方法中使用局部变量遮蔽您的字段电影。这很少是一个好主意,因为它可能导致各种微妙的错误。

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

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

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

例如,假设电影的核心属性是其标题,您可以使用:

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

这就是你要比较的东西。或者也许进入你的电影列表(你仍然希望至少进行一次&#34;集成&#34;测试,以确保getSortedMovies ......()完成它应该做的事情。)

如果你认为你需要模拟电影对象,那么你的设计就不好了。就这么简单。如果它不是&#34;那&#34;如上所示简单来实例化一个Movie对象,而不是你应该启用它。

因为否则,您必须执行以下操作:

Movie mockedMovieA = createMock(Movie.class);

然后提供mock预期的所有属性,如:

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

那将是非常麻烦和错误的。

所以,正如所说的那样,你应该研究核心的事情:创建一个允许你使用&#34;真实&#34;单元测试中的电影对象。如果你的Movie类包含很多东西,那么这是不可能的......那是一个明确的指示,那就是你的Movie类太大了,做了不属于它的东西。

解决此类问题的第一种方式&#34;太大&#34;问题:你可以分开一部电影&#34;包含当前Movie类的核心方法的接口,例如getTitle(),getReleaseDate()等等。然后所有您的代码只适用于该界面...这很容易被嘲笑;或由更多&#34;愚蠢的&#34;仅测试课程。

答案 1 :(得分:0)

  

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

使用UnitTest测试可观察行为

这意味着无论方法如何实现,都会检查返回集合中的对象是否具有正确的顺序。

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