说明
- 一般来说,封装的工具类库、服务端接口的核心service,都应该提供相应的单元测试;
- junit 中有2个 @Test 注解:junit4 中开始提供
@org.junit.Test
,junit5 中开始提供@org.junit.jupiter.api.Test
,这2个注解在普通java项目中的使用基本相同,需要注意的是低版本 springboot 中可能没有 @org.junit.jupiter.api.Test,只能使用 @org.junit.Test 。
junit的使用
- 包、类的路径与源码保持一致,测试类通常命名为原类名+Test,测试方法名一般命名为test+原方法名
- 测试方法不能有入参、返回值类型要是void
public class XxxTest {
@Before //执行每个测试方法之前都会先执行@Before标注的方法
public void init(){
}
@After //执行每个测试方法之后都会执行@After标注的方法
public void destroy(){
}
@Test
public void testA(){
//提示信息可以缺省
Assert.assertEquals("提示信息", "期望数据", "实际数据");
}
@Test
public void testB(){
}
}
spring整合junit
依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.8.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
编写单元测试
@RunWith(SpringRunner.class) //提供spring容器环境,这样@Autowired之类的注解才能注入所需依赖。如果当前测试类不需要spring容器环境,可缺省
@ContextConfiguration(locations = "classpath:spring-config.xml") //指定配置文件的位置
// @ContextConfiguration(locations = {"classpath:spring-config1.xml","classpath:spring-config2.xml"}) //有多个时写成数组
public class UserMapperTest {
@Autowired //注入要测试的类的实例
private UserMapper userMapper;
@BeforeClass //在测试这个类之前执行,常用于初始化静态成员变量
public static void BeforeClass(){
}
@AfterClass //在测试这个类之后执行
public static void AfterClass(){
}
@Before //每个测试方法执行之前都会执行此方法,常用于初始化实例的成员变量
public void before(){
}
@After //每个测试方法执行完毕后都会执行此方法
public void after(){
}
@Test //测试方法
public void findUserByIdTest(){
User user = userMapper.findUserById(1);
//使用的Assert是junit中的,不要导错了
Assert.assertEquals("返回的User对象与预期不符,未通过测试", user, new User(1,"chy",20));
}
@Ignore //测试这个类时会忽略|跳过此方法,可备注一些信息
// @Ignore("对应方法还存在bug,暂不测试")
public void updateUserTest(){
//.....
}
}
注意
@RunWith(SpringRunner.class)
,SpringRunner 是 SpringJUnit4ClassRunner 的别名,2个都可以- 在测试类前后执行用的是 @BeforeClass、@AfterClass,不是 @BeforeTestClass、@AfterTestClass
- @BeforeClass、@AfterClass 标注的方法必须是没有入参、返回值是void的静态方法
测试
选择JUnit
springboot整合junit
依赖
用Spring Initializr创建springboot项目时,默认会自动添加junit的依赖。如果不使用Spring Initializr,可以手动添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
junit-vintage-engine是使用老版本junit所需的依赖,不需要,使用<exclusions>排除,当然留着也行。
编写单元测试
@RunWith(SpringRunner.class)
@SpringBootTest // @SpringBootTest(classes = {MallApplication.class} ) //指定源码中的引导类,如果源码中只有1个引导类,可缺省classes属性。
// @WebAppConfiguration //模拟ServletContext、提供web环境,如果这个测试类不涉及web,可缺省
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@BeforeClass
public static void BeforeClass(){
}
@AfterClass
public static void AfterClass(){
}
@Before
public void before(){
}
@After
public void after(){
}
@Test
public void testFindUserById(){
User user = userMapper.findUserById(1);
Assert.assertEquals("返回的User对象与预期不符,未通过测试", user, new User(1,"chy",20));
}
@Ignore
public void testUpdateUser(){
//.....
}
}
在高版本springboot(springboot 2.2 版本)中, spring-boot-starter-test 已经移除了junit 的部分依赖
- 不需要写、也不再提供 @RunWith 注解;
- 不再提供 Assert 类,可以使用 Assertions 或spring的 Assert 代替。
常用技巧
1、每个测试类上都要写@RunWith、@SpringBootTest,很麻烦,可以封装为一个类,测试类都继承该类
@RunWith(SpringRunner.class)
@SpringBootTest
public class BaseTest {
}
2、打包测试
一个测试类一个测试类地去点击运行,很麻烦,可以把测试类打包到一个类中,运行该类即可
@RunWith(Suite.class)
@Suite.SuiteClasses({UserMapperTest.class, GooodsMapperTest.class}) //数组中写要运行的测试类
public class TestSuits {
}
3、私有方法的常见测试方式
- 直接在目标类中写测试,比如直接写个main方法
- 将目标代码拷贝到单元测试中
- 将方法改为public,测试完再改回去
- 将方法改为public,在方法上标注guava的 @VisibleForTesting 或 jetbrains的 @TestOnly,这2个注解只是声明这个public权限仅用于测试,并没有其它实际作用,在非测试类中一样可以调用这个public方法,靠开发自觉遵守声明
- 通过反射调用私有方法(推荐)
//spring-test提供的工具类,参数分别是目标类实例、目标方法名、实参表,返回目标方法的返回值
T t = ReflectionTestUtils.invokeMethod(xxxServiceImpl, "methodName", args...);
常见问题
IDEA执行单元测试时报错
Error running ‘XxxTest.testXxx’: Command line is too long. Shorten command line for XxxTest.testXxx or also for JUnit default configuration?
可在父项目的 workspace.xml 中找到 <component name="PropertiesComponent">
,加一个子元素
<property name="dynamic.classpath" value="true" />