尽管存在不同的论点,Mockito的模拟返回相同的值

时间:2016-01-01 18:55:58

标签: java mockito

package pl.mielecmichal.news.services.news;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import pl.mielecmichal.news.entities.news.News;
import pl.mielecmichal.news.entities.newssources.NewsSource;
import pl.mielecmichal.news.repositories.news.NewsRepository;

import static java.util.Arrays.asList;
import static org.mockito.Mockito.*;

import java.net.MalformedURLException;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


public class NewsServiceTest {

    NewsService newsService;

    NewsRepository newsRepository;

    private static final String FIRST_AUTHOR = "first@mail.com";
    private static final String FIRST_TITLE = "First Title";
    private static final String FIRST_CONTENT = "First Content Content Content";
    private static final String FIRST_URL = "http://localhost/first";

    private static final String SECOND_AUTHOR = "second@mail.com";
    private static final String SECOND_TITLE = "Second";
    private static final String SECOND_CONTENT = "Second Content";

    private static final String THIRD_AUTHOR = "third@mail.com";
    private static final String THIRD_TITLE = "Third Title";
    private static final String THIRD_CONTENT = "Third Content";

    private final News firstNews = firstCorrectNews();
    private final News secondNews = secondCorrectNews();
    private final News thirdNews = thirdCorrectNews();
    private final NewsSource source = correctSource();

    public NewsServiceTest() throws MalformedURLException {

    }

    @Before
    public void setUp() throws MalformedURLException {
        newsRepository = mock(NewsRepository.class);
        newsService = new NewsService(newsRepository);
    }

    @Test
    public void saveNewNewses_savedNewsesGivenAgain_shouldSaveOnlyNew() {
        // given
        List<News> newses = new ArrayList<>();
        newses.add(firstNews);
        newses.add(secondNews);

        when(newsRepository.countByNewsSourceAndAuthorAndTitle(source, FIRST_AUTHOR, FIRST_TITLE)).thenReturn(0L);
        when(newsRepository.countByNewsSourceAndAuthorAndTitle(source, SECOND_AUTHOR, SECOND_TITLE)).thenReturn(1L);

        // when
        newsService.saveNewNewses(newses);

        // then
        verify(newsRepository, times(1)).save(asList(firstNews));
        verify(newsRepository, never()).save(newses);
    }

    private News firstCorrectNews() {
        News news = new News();
        news.setAuthor(FIRST_AUTHOR);
        news.setTitle(FIRST_TITLE);
        news.setContent(FIRST_CONTENT);
        news.setNewsSource(source);
        return news;
    }

    private News secondCorrectNews() {
        News news = new News();
        news.setAuthor(SECOND_AUTHOR);
        news.setTitle(SECOND_TITLE);
        news.setContent(SECOND_CONTENT);
        news.setNewsSource(source);
        return news;
    }

    private News thirdCorrectNews() {
        News news = new News();
        news.setAuthor(THIRD_AUTHOR);
        news.setTitle(THIRD_TITLE);
        news.setContent(THIRD_CONTENT);
        news.setNewsSource(source);
        return news;
    }

    private NewsSource correctSource() throws MalformedURLException {
        NewsSource source = new NewsSource();
        source.setUrl(new URL(FIRST_URL));
        source.setUpdateTime(LocalDateTime.now());
        return source;
    }

}

我在调试器下检查过,countBy方法总是返回O,但是在我的SUT中参数是不同的和正确的。看起来Mockito没有 区分方法参数。干杯!

我添加完整的源代码以显示常量是正确的。

2 个答案:

答案 0 :(得分:2)

虽然问题主要是你的字段的排序,但你可以采取一些措施来减少再次出现这种错误的可能性,并清理你的测试。

首先,您的三种方法 - firstCorrectNewssecondCorrectNewsthirdCorrectNews - 所有参数都略有不同。统一他们的目的更有意义。

private News correctNews(final String author, final String title, final String content, final NewsSource source) {
    final News news = new News();
    news.setAuthor(author);
    news.setTitle(title);
    news.setContent(content);
    news.setNewsSource(source);
    return news;
}

如果你使用这个方法来引导你的测试news对象,那么你每次都被迫传入一个源代码,这样你就不会被任何东西所吸引。这总体上取决于测试对象的状态。

虽然我们在这里,但也值得修改correctSource方法,以便我们传入URL而不是再次假设状态。

private NewsSource correctSource(final String url) throws MalformedURLException {
    final NewsSource source = new NewsSource();
    source.setUrl(new URL(url));
    source.setUpdateTime(LocalDateTime.now());
    return source;
}

接下来,我们可以利用Mockito的跑步者课程,这样我们就不必在@Before条款中修改模拟。这样可以使代码更小,并且可以满足对模拟类和测试类的期望。

@RunWith(MockitoJUnitRunner.class)
public class NewsServiceTest {

    @Mock
    NewsRepository newsRepository;

    @InjectMocks
    NewsService newsService;

    // other code to follow

}

现在,让我们把它们放在一起。 与您正在测试的完全相同,主要区别在于:

  • 您的代码中的重复次数要少得多,特别是在引导预期数据时
  • 你的嘲笑是明确定义的
  • 您真正关心的所有测试数据都在您的特定测试中,这有助于您想要编写更多测试
  • 您的测试数据也在范围内隔离,允许您并行运行此测试


@RunWith(MockitoJUnitRunner.class)
public class NewsServiceTest {

    @Mock
    NewsRepository newsRepository;

    @InjectMocks
    NewsService newsService;

    @Test
    public void saveNewNewses_savedNewsesGivenAgain_shouldSaveOnlyNew() {
        // given
        final String FIRST_AUTHOR = "first@mail.com";
        final String FIRST_TITLE = "First Title";
        final String FIRST_CONTENT = "First Content Content Content";
        final String URL = "http://localhost/first";
        final String SECOND_AUTHOR = "second@mail.com";
        final String SECOND_TITLE = "Second";
        final String SECOND_CONTENT = "Second Content";

        final List<News> newses = new ArrayList<>();

        final NewsSource newsSource = correctSource(URL);
        final News firstNews = correctNews(FIRST_AUTHOR, FIRST_TITLE, FIRST_CONTENT, newsSource);
        final News secondNews = correctNews(SECOND_AUTHOR, SECOND_TITLE, SECOND_CONTENT, newsSource);

        newses.add(firstNews);
        newses.add(secondNews);

        // when

        when(newsRepository.countByNewsSourceAndAuthorAndTitle(newsSource, FIRST_AUTHOR, FIRST_TITLE)).thenReturn(0L);
        when(newsRepository.countByNewsSourceAndAuthorAndTitle(newsSource, SECOND_AUTHOR, SECOND_TITLE)).thenReturn(1L);
        newsService.saveNewNewses(newses);

        // then
        verify(newsRepository).save(asList(firstNews));
        verify(newsRepository, never()).save(newses);
    }

    private News correctNews(final String author, final String title, final String content, final NewsSource source) {
        final News news = new News();
        news.setAuthor(author);
        news.setTitle(title);
        news.setContent(content);
        news.setNewsSource(source);
        return news;
    }


    private NewsSource correctSource(final String url) throws MalformedURLException {
        NewsSource source = new NewsSource();
        source.setUrl(new URL(url));
        source.setUpdateTime(LocalDateTime.now());
        return source;
    }
}

答案 1 :(得分:0)

好的,问题是初始化新手和源的顺序。

当我创建firstNews,secondNews,thirdNews时,源对象仍为null。但在我的测试中,它已完全初始化。

private final NewsSource source = correctSource(); //should be here
private final News firstNews = firstCorrectNews();
private final News secondNews = secondCorrectNews();
private final News thirdNews = thirdCorrectNews();
private final NewsSource source = correctSource(); //not here