尽管参数不同,但 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 中是不同且正确的。看起来莫基托没有区分方法参数。干杯!

我添加了完整的源代码以表明常量是正确的。

虽然问题主要在于字段的顺序,但您可以采取一些措施来降低再次发生此错误的可能性,并清理测试。

首先,您的三种方法 - 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 的 runner 类,这样我们就不必在 @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;
    }
}

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

当我创建第一新闻,第二新闻,第三新闻时,源对象还为空。但是在我的测试中,它是完全初始化的。

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

相关内容

  • 没有找到相关文章

最新更新