记录junit 测试框架使用
springboot 测试类
- 测试基类配置
@RunWith(SpringRunner.class)
@SpringBootTest
@WebAppConfiguration
@ContextConfiguration(initializers=ConfigFileApplicationContextInitializer.class)
@Slf4j
public class BreakfastApplicationTests {
}
springboot 测试类编写时 可以通过申明一个基类 同时添加@SpringBootTest与@RunWith注解, 如果需要访问数据库,则需要在代码中申明 dataSource
Ps: 如果测试需要单独的dataDource 则可以在基类中自行配置数据源
- 测试类编写
@Slf4j
@ActiveProfiles("dev")
@TestPropertySource("classpath:application-dev.yml")
public class WalletServiceTest extends BreakfastApplicationTests {
}
通过@ActiveProfiles 指定对应的环境, 通过@TestPropertySource 指定需要加载的配置文件
解决JUNIT测试框架不支持多线程测试
- 使用thread.join
@Test
public void updateTest() {
for (int i = 0; i < 30; i++) {
Runnable run = new Runnable() {
public void run() {
WalletDto walletDto = new WalletDto();
walletDto.setTotalBalance(new BigDecimal(0.5).multiply(new BigDecimal(new Random().nextInt(100))));
walletDto.setFrozenAmount(new BigDecimal(0.5).multiply(new BigDecimal(new Random().nextInt(50))));
walletDto.setPassword("11111111");
walletDto.setPwdSalt("dhxh");
walletDto.setCreateTime(new Date(System.currentTimeMillis()));
walletDto.setDeleteFlag(Boolean.FALSE);
walletDto.setId(3);
walletDto.setOperator(2);
walletDto.setStoreId(1);
walletDto.setUpdateTime(new Date(System.currentTimeMillis()));
walletDto.setDeleteTime(new Date(System.currentTimeMillis()));
walletService.update(walletDto);
}
};
/* 使用线程池 如果没有阻塞主线程,junit在主线程执行完后,会调用System.exit() 方法, 停止JVM*/
executorConfig.asyncServiceExecutor().execute(run);
/* 不使用线程池 */
Thread thread = new Thread(run);
thread.start();
try {
/*加入主线程 或thread.sleep(太low)*/
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 使用countDownLatch
/**
* 一种简单的方法是使用CountDownLatch.
*
* 使用CountDownLatch latch = new CountDownLatch(30)初始化CountDownLatch.
* 传递每个计算器可运行对锁存器的引用.在run()方法结束时,调用latch.countDown().
* 在方法结束时调用latch.await().这将阻塞,直到latch.countDown()被调用30次(即所有线程完成时).
*/
@Test
public void update() {
CountDownLatch countDownLatch = new CountDownLatch(30);
for (int i = 0; i <= 30; i++) {
executorConfig.asyncServiceExecutor().execute(() -> {
WalletDto walletDto = new WalletDto();
walletDto.setTotalBalance(new BigDecimal(0.5).multiply(new BigDecimal(new Random().nextInt(100))));
walletDto.setFrozenAmount(new BigDecimal(0.5).multiply(new BigDecimal(new Random().nextInt(50))));
walletDto.setPassword("11111111");
walletDto.setPwdSalt("dhxh");
walletDto.setCreateTime(new Date(System.currentTimeMillis()));
walletDto.setDeleteFlag(Boolean.FALSE);
walletDto.setId(3);
walletDto.setOperator(2);
walletDto.setStoreId(1);
walletDto.setUpdateTime(new Date(System.currentTimeMillis()));
walletDto.setDeleteTime(new Date(System.currentTimeMillis()));
log.info("walletDto = {}", walletDto);
walletService.update(walletDto);
countDownLatch.countDown();
log.info("count = {}", countDownLatch.getCount());
});
}
try {
countDownLatch.await(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Ps: 如果没有阻塞主线程, junit会在主线程执行完之后 调用System.exit(), 即使子线程没有执行完。
- 其实junit是将test作为参数传递给了TestRunner的main函数。并通过main函数进行执行。test函数在main中执行。如果test执行结束,那么main将会调用System.exit(0);
- 即使还有其他的线程在运行,main也会调用System.exit(0);
- System.exit()是系统调用,通知系统立即结束jvm的运行,即使jvm中有线程在运行,jvm也会停止的。所以会出现之前的那种情况。其中System.exit(0);的参数如果是0,表示系统正常退出,如果是非0,表示系统异常退出。
public static void main(String[] args) {
TestRunner aTestRunner = new TestRunner();
try {
TestResult r = aTestRunner.start(args);
if (!r.wasSuccessful()) {
System.exit(1);
}
System.exit(0);
} catch (Exception var3) {
System.err.println(var3.getMessage());
System.exit(2);
}
}