为了提高软件开发质量,我们需要对所开发的功能进行单元测试,在Spring Boot中,进行单元测是非常容易的。在开发过程中,认真准备单元测试用例,不仅可以保证代码质量,也便于进行回归测试。今后在修改或代码重构时,通过回归测试,可以保证修改和代码重构的正确性。
为了支持Spring下的单位测试,我们需要在pom.xml中添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
我们在src/test/java中创建单元测试用例,在我里我们以测试ProductController为例,先来讲解测试微服务:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class ProductControllerTests {
@Autowired
private MockMvc mvc;
@Before
public void setUp() throws Exception {
}
@Test
public void testAll() {
try {
mvc.perform(MockMvcRequestBuilders.get("/products").
accept(MediaType.APPLICATION_JSON)).andExpect(new ResultMatcher() {
@Override
public void match(MvcResult result) throws Exception {
System.out.println("result:" + result.getResponse().getContentAsString() + "!");
Assert.assertEquals("1", "1");
}});
} catch (Exception e) {
fail("异常:" + e.getMessage() + "!");
}
}
@Test
public void testAddProduct() {
// Assert.assertEquals("1", "2");
// fail("添加产品失败");
}
@Test
public void testOne() {
}
@Test
public void testUpdateProduct() {
}
@Test
public void testDeleteProduct() {
}
@Test
public void testTestJdbc() {
}
@Test
public void testTestTransaction() {
}
}
第1行:所有Spring的测试用例均需写这个注解;
第2行:测试Spring Boot微服务时必须加这个注解,会将服务启动在一个临时端口上;
第3行:测试SpringMVC时需要用到的注解;
第5、6行:测试SpringMvc时需要的对象;
第12~26行:以列出所有产品的服务为例,实现一个完整的测试用例。所有测试用例均需加@Test注解;
第15行:通过mvc发起HTTP请求;
第16行:通过andExpect函数来检查结果是否正确;
第16~22行:定义一个ResultMatcher对象,可以对响应进行检查,通过Assert系列函数,来判断服务是否正确;
可以通过类似的方式对其他服务进行相同的测试,这样当我们对服务进行修改时,我们就可以通过运行这些测试用例,保证我们的修改是正确且安全的。
选中ProductControllerTest类,点击右键选择Run as => JUnit Test,运行结果如下所示:
如图所示:我们可以取到响应结果,即以Json格式给出的所有产品的列表。Junit测试用例的运行结果如下所示:
在实际项目中,比较难于测试的,除了SpringMvc以外,就是数据库部分了。我们在项目中数据库增删改采用了JPA,而数据库查询操作采用了JdbcTemplate技术。
我们先来看JPA测试用例的编写:
@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class ProductRepositoryTest {
@Autowired
ProductRepository repository;
@Test
@Rollback(false)
public void test() {
Product product = new Product();
product.setProductName("XXXXXXXXXX");
//fail("Not yet implemented");
repository.save(product);
Assert.assertEquals("1", "1");
}
}
第1行:所有Spring的测试用例均需添加的注解;
第2行:测试JPA时需要添加的注解;
第3行:当使用真实环境数据库时需要添加的注解;
第5、6行:由于我们JPA使用ProductRepository接口,所以从Spring获取该接口的实现类的实例;
第8、9行:由于JPA测试时,所有对数据库的操作,在测试结束时会自动回滚,所以测试结束时看不到脏数据,这是一个很好的特性,测试不影响数据库正确数据。但是如果我们希望测试结束后看到数据,需要加@Rollback(false)注解;
下面我们来看JdbcTemplate的测试用例编写,由于我们的DAO实现类ProductMysqlDao是通过@Service来注解的,我们通过两种方式来进行数据库查询操作,如下所示:
public List<ProductVo> getProducts() {
Object[] params = new Object[1];
params[0] = 1; // new BeanPropertyRowMapper(Account.class)
// 方法1
List<ProductVo> recs = jdbcTemplate.query("select product_name, image_url, price from t_product where product_category_id=?", params, new BeanPropertyRowMapper(ProductVo.class));
// 方法2
/*List<ProductVo> recs = jdbcTemplate.query("select product_name, image_url, price from t_product where product_category_id=?", params, (rs, num) -> {
ProductVo vo = new ProductVo();
vo.setProductName(rs.getString(1) + "---M2");
return vo;
});*/
return recs;
}
public List<ProductVo> getProducts2() {
Object[] params = new Object[1];
params[0] = 1; // new BeanPropertyRowMapper(Account.class)
// 方法1
//List<ProductVo> recs = jdbcTemplate.query("select product_name, image_url, price from t_product where product_category_id=?", params, new BeanPropertyRowMapper(ProductVo.class));
// 方法2
List<ProductVo> recs = jdbcTemplate.query("select product_name, image_url, price from t_product where product_category_id=?", params, (rs, num) -> {
ProductVo vo = new ProductVo();
vo.setProductName(rs.getString(1) + "---M2");
return vo;
});
return recs;
}
接下来我们就来测试这两个方法,如下所示:
@RunWith(SpringRunner.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@SpringBootTest(classes = MseApplication.class)
public class ProductMysqlDaoTest {
@Autowired
private ProductMysqlDao dao;
@Test
public void testGetProducts() {
List<ProductVo> vos = dao.getProducts();
for (ProductVo vo : vos) {
System.out.println("####:" + vo.getProductId() + "=>" + vo.getProductName() + "!");
}
Assert.assertEquals("1", "1");
}
@Test
public void testGetProducts2() {
List<ProductVo> vos = dao.getProducts2();
for (ProductVo vo : vos) {
System.out.println("####:" + vo.getProductId() + "=>" + vo.getProductName() + "!");
}
Assert.assertEquals("1", "1");
}
}
在这个测试类中,我们不仅添加对JdbcTemplate的测试,而且还添加了Service层的测试,这样我们就可以对Spring应用中所有的组件进行单元测试了。