@RunWith(SpringRunner.class) 与@RunWith(MockitoJUnitRunner.class)
@RunWith(SpringRunner.class) vs @RunWith(MockitoJUnitRunner.class)
我在使用 mockito 进行 junit 测试时使用 @RunWith(MockitoJUnitRunner.class)
。但现在我正在使用 spring 引导应用程序并尝试使用 @RunWith(SpringRunner.class)
。使用 @RunWith(SpringRunner.class)
是否比使用 @RunWith(MockitoJUnitRunner.class)
有任何优势?我还能使用 @Injectmock
、@Mock
、@Spy
和 @RunWith(SpringRunner.class)
等功能吗
使用SpringRunner.class
时,Spring提供对应的注解:
@MockBean
@SpyBean
模拟通过 @Autowired
注释注入到被测对象。要启用此功能测试必须用
注释
@SpringBootTest
或
@TestExecutionListeners(MockitoTestExecutionListener.class)
更多细节和示例可以在官方文档中找到:Mocking and Spying Beans
SpringRunner
支持加载 Spring ApplicationContext
并将 bean @Autowired
加载到您的测试实例中。 它实际上做的远不止这些(在 Spring 参考手册中介绍),但这是基本思想。
然而,MockitoJUnitRunner
支持使用 Mockito 创建模拟和间谍。
但是,对于 JUnit 4,您一次只能使用一个 Runner
。
因此,如果您想同时使用 Spring 和 Mockito 的支持,您只能选择 一个 的跑步者。
但你很幸运,因为除了 runners 之外,Spring 和 Mockito 还提供 rules。
例如,您可以使用 Spring runner 和 Mockito 规则,如下所示。
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@Mock
MyService myService;
// ...
}
不过,通常情况下,如果您正在使用 Spring 启动并且需要从 Spring ApplicationContext
中模拟一个 bean,您会然后使用 Spring Boot 的 @MockBean
支持而不是简单地 @Mock
.
根据 JavaDoc:
SpringRunner is an alias for the SpringJUnit4ClassRunner
.
To use this class, simply annotate a JUnit 4 based test class with @RunWith(SpringRunner.class)
.
If you would like to use the Spring TestContext
Framework with a runner other than this one, use org.springframework.test.context.junit4.rules.SpringClassRule
and org.springframework.test.context.junit4.rules.SpringMethodRule
.
以及 TestContext
的 JavaDoc:
TestContext
encapsulates the context in which a test is executed, agnostic of the actual testing framework in use.
方法getApplicationContext()
:
Get the application context for this test context, possibly cached.
Implementations of this method are responsible for loading the application context if the corresponding context has not already been loaded, potentially caching the context as well.
因此,SpringRunner 确实加载上下文并负责维护它。例如,如果你想将数据持久化到嵌入式数据库中,比如 H2 内存数据库,你必须使用 SpringRunner.class
;并且,要清理表格以删除每次测试后插入的记录,您可以使用 @DirtiesContext
注释测试以告诉 Spring 清理它。
但是,这已经是一个集成或组件测试。如果你的测试是纯单元测试,你不必加载数据库,或者你只是想验证某个依赖的某个方法是否被调用,MockitoJUnit4Runner
就足够了。您只需使用 @Mock
和 Mockito.verify(...)
即可通过测试。而且速度快了很多。
测试应该很快。尽可能快地。因此,只要有可能,请使用 MockitoJUnit4Runner
来加快速度。
您完全可以将 SpringRunner 用于单元测试和集成测试。
SpringRunner Tutorial
2019 年 11 月场景:spring-引导:2.1.1.RELEASE
- 你有一个spring启动api休息
- 您需要测试名为 MySuperSpringService
的服务
- 但是,在 MySuperSpringService 内部,还需要两个自动装配。一个执行 sql select (MyJpaRepository) 另一个调用外部 api rest (MyExternalApiRest)
@Service
public class MySuperSpringService {
@Autowired
private MyRepository innerComponent1;
@Autowired
private MyExternalApiRest innerComponent2;
public SomeResponse doSomething(){}
}
如何测试 MySuperSpringService 模拟数据库和外部 api 休息?
因此,为了测试需要另一个 spring beans 的服务 MySuperSpringService:MyJpaRepository 和 MyExternalApiRest,您需要使用 @ 模拟它们MockBean 并根据需要创建结果。
import static org.mockito.Mockito.when;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import junit.framework.TestCase;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = your.package.Application.class)
public class MySuperSpringServiceTest extends TestCase {
@Autowired
private MySuperSpringService serviceToTest;
@MockBean
private MyRepository myRepository;
@MockBean
private MyExternalApiRest myExternalApiRest;
@Before
public void setUp() {
Object myRepositoryResult = new Object();
//populate myRepositoryResult as you need
when(myRepository.findByClientId("test.apps.googleusercontent.com"))
.thenReturn(myRepositoryResult);
Object myExternalApiRestResult = new Object();
//populate myExternalApiRestResult as you need
when(myExternalApiRest.listUserRoles("john@doe.com")).thenReturn(myExternalApiRestResult);
}
@Test
public void testGenerateTokenByGrantTypeNoDatabaseNoGoogleNoSecurityV1(){
SomeResponse response = serviceToTest.doSomething();
//put your asserts here
}
}
我在使用 mockito 进行 junit 测试时使用 @RunWith(MockitoJUnitRunner.class)
。但现在我正在使用 spring 引导应用程序并尝试使用 @RunWith(SpringRunner.class)
。使用 @RunWith(SpringRunner.class)
是否比使用 @RunWith(MockitoJUnitRunner.class)
有任何优势?我还能使用 @Injectmock
、@Mock
、@Spy
和 @RunWith(SpringRunner.class)
使用SpringRunner.class
时,Spring提供对应的注解:
@MockBean
@SpyBean
模拟通过 @Autowired
注释注入到被测对象。要启用此功能测试必须用
@SpringBootTest
或
@TestExecutionListeners(MockitoTestExecutionListener.class)
更多细节和示例可以在官方文档中找到:Mocking and Spying Beans
SpringRunner
支持加载 Spring ApplicationContext
并将 bean @Autowired
加载到您的测试实例中。 它实际上做的远不止这些(在 Spring 参考手册中介绍),但这是基本思想。
然而,MockitoJUnitRunner
支持使用 Mockito 创建模拟和间谍。
但是,对于 JUnit 4,您一次只能使用一个 Runner
。
因此,如果您想同时使用 Spring 和 Mockito 的支持,您只能选择 一个 的跑步者。
但你很幸运,因为除了 runners 之外,Spring 和 Mockito 还提供 rules。
例如,您可以使用 Spring runner 和 Mockito 规则,如下所示。
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@Mock
MyService myService;
// ...
}
不过,通常情况下,如果您正在使用 Spring 启动并且需要从 Spring ApplicationContext
中模拟一个 bean,您会然后使用 Spring Boot 的 @MockBean
支持而不是简单地 @Mock
.
根据 JavaDoc:
SpringRunner is an alias for the
SpringJUnit4ClassRunner
. To use this class, simply annotate a JUnit 4 based test class with@RunWith(SpringRunner.class)
. If you would like to use the SpringTestContext
Framework with a runner other than this one, useorg.springframework.test.context.junit4.rules.SpringClassRule
andorg.springframework.test.context.junit4.rules.SpringMethodRule
.
以及 TestContext
的 JavaDoc:
TestContext
encapsulates the context in which a test is executed, agnostic of the actual testing framework in use.
方法getApplicationContext()
:
Get the application context for this test context, possibly cached. Implementations of this method are responsible for loading the application context if the corresponding context has not already been loaded, potentially caching the context as well.
因此,SpringRunner 确实加载上下文并负责维护它。例如,如果你想将数据持久化到嵌入式数据库中,比如 H2 内存数据库,你必须使用 SpringRunner.class
;并且,要清理表格以删除每次测试后插入的记录,您可以使用 @DirtiesContext
注释测试以告诉 Spring 清理它。
但是,这已经是一个集成或组件测试。如果你的测试是纯单元测试,你不必加载数据库,或者你只是想验证某个依赖的某个方法是否被调用,MockitoJUnit4Runner
就足够了。您只需使用 @Mock
和 Mockito.verify(...)
即可通过测试。而且速度快了很多。
测试应该很快。尽可能快地。因此,只要有可能,请使用 MockitoJUnit4Runner
来加快速度。
您完全可以将 SpringRunner 用于单元测试和集成测试。 SpringRunner Tutorial
2019 年 11 月场景:spring-引导:2.1.1.RELEASE
- 你有一个spring启动api休息
- 您需要测试名为 MySuperSpringService 的服务
- 但是,在 MySuperSpringService 内部,还需要两个自动装配。一个执行 sql select (MyJpaRepository) 另一个调用外部 api rest (MyExternalApiRest)
@Service
public class MySuperSpringService {
@Autowired
private MyRepository innerComponent1;
@Autowired
private MyExternalApiRest innerComponent2;
public SomeResponse doSomething(){}
}
如何测试 MySuperSpringService 模拟数据库和外部 api 休息?
因此,为了测试需要另一个 spring beans 的服务 MySuperSpringService:MyJpaRepository 和 MyExternalApiRest,您需要使用 @ 模拟它们MockBean 并根据需要创建结果。
import static org.mockito.Mockito.when;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import junit.framework.TestCase;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = your.package.Application.class)
public class MySuperSpringServiceTest extends TestCase {
@Autowired
private MySuperSpringService serviceToTest;
@MockBean
private MyRepository myRepository;
@MockBean
private MyExternalApiRest myExternalApiRest;
@Before
public void setUp() {
Object myRepositoryResult = new Object();
//populate myRepositoryResult as you need
when(myRepository.findByClientId("test.apps.googleusercontent.com"))
.thenReturn(myRepositoryResult);
Object myExternalApiRestResult = new Object();
//populate myExternalApiRestResult as you need
when(myExternalApiRest.listUserRoles("john@doe.com")).thenReturn(myExternalApiRestResult);
}
@Test
public void testGenerateTokenByGrantTypeNoDatabaseNoGoogleNoSecurityV1(){
SomeResponse response = serviceToTest.doSomething();
//put your asserts here
}
}