给定以下@Component
类:
@Component
public class MovieFinderImpl implements MovieFinder {
@Autowired
private Movie movie;
@Override
public List<Movie> findAll() {
List<Movie> movies = new ArrayList<>();
movies.add(movie);
return movies;
}
}
我试图学习如何在不做集成测试的情况下对这个示例组件进行单元测试(所以测试类上没有@RunWith(SpringRunner.class)
和@SpringBootTest
注释)
当我的测试类看起来像这样:
public class MovieFinderImplTest {
@InjectMocks
private MovieFinderImpl movieFinderImpl;
@Mock
public Movie movieMock;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
movieMock.setTitle("test");
movieMock.setDirector("directorTest");
}
@Test
public void testFindAll() {
List<Movie> movies = movieFinderImpl.findAll();
Assert.assertNotNull(movies.get(0));
String expectedTitle = "test";
String actualTitle = movies.get(0).getTitle();
Assert.assertTrue(String.format("The expected name is %s, but the actual name is %s", expectedTitle, actualTitle), expectedTitle.equals(actualTitle));
String expectedDirector = "testDirector";
String actualDirector = movies.get(0).getDirector();
Assert.assertTrue(String.format("The expected name is %s, but the actual name is %s", expectedDirector, actualDirector), expectedDirector.equals(actualDirector));
}
}
…mock不是空的,但是mock类变量是空的,因此:
java.lang.AssertionError: The expected name is test, but the actual name is null
我已经浏览了http://www.vogella.com/tutorials/Mockito/article.html,但是无法找到如何在mock上设置类变量的示例。
如何正确地模拟电影对象?更一般地说,这是测试MovieFinderImp类的正确方法吗?我的灵感只是组件测试是这个博客https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4
(ps:我想知道我是否应该在这个测试类中实际测试movie.get()
方法…也许我的测试设计是错误的)。
在@Before方法中mock的方式有一个问题。而不是
movieMock.setTitle("test");
movieMock.setDirector("directorTest");
像那样做
Mockito.when(movieMock.getTitle()).thenReturn("test");
Mockito.when(movieMock.getDirector()).thenReturn("directorTest");
模拟对象不是真正的对象,没有属性,只有你需要添加的模拟行为。使用setter不会对它们做任何事情。除非指定指定的行为,否则getter将返回null。这可以用when…thenReturn结构:
when(movieMock.getTitle()).thenReturn("movie title");
也许没有理由嘲笑电影。你可以使用@Spy注释,这样它将是一个具有真实属性的真实对象,同时你可以覆盖一些方法。
当构建完整的对象很困难并且有很多依赖关系或复杂的行为时,mock是非常有用的,但是如果Movie是bean,那么mock可能是多余的。例如:public class MovieFinderImplTest {
@InjectMocks
private MovieFinderImpl movieFinderImpl;
@Spy /* <- See the change from mock */
public Movie movie = new Movie();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
/* modified like a normal object */
movie.setTitle("test");
movie.setDirector("directorTest");
}
参见mock和spy之间的区别。互联网上有很多关于什么应该被嘲笑,什么不应该被嘲笑的讨论。如果你仍然喜欢嘲笑电影,那么marians27和VinayVeluri的答案就是你的正确答案。
你必须这样做;
import static org.mockito.Mockito.when;
when(movieMock.getTitle()).thenReturn("movie title");
when(movieMock.getDirector()).thenReturn("movie director");
@InjectMocks
只帮助注入非空对象,不处理值。对于值,必须显式地设置需要测试的值。
如果您使用MockitoJunitRunner
,则不需要调用MockitoAnnotations.initMocks(this);
,该运行程序负责。