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没有 区分方法参数。干杯!
我添加完整的源代码以显示常量是正确的。
答案 0 :(得分:2)
虽然问题主要是你的字段的排序,但你可以采取一些措施来减少再次出现这种错误的可能性,并清理你的测试。
首先,您的三种方法 - firstCorrectNews
,secondCorrectNews
和thirdCorrectNews
- 所有参数都略有不同。统一他们的目的更有意义。
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