SpringBootTest
可以在运行基于Spring Boot的测试的测试类上指定的注释。当没有定义特定的@ContextConfiguration(loader=…)时,使用SpringBootContextLoader作为缺省ContextLoader。
- 当未使用嵌套的@Configuration且未指定显式类时,自动搜索@SpringBootConfiguration。
- 允许使用properties属性定义自定义环境属性。
- 允许使用args属性定义应用程序参数。
- 提供对不同web环境模式的支持,包括启动一个完全运行的web服务器,在一个定义的或随机的端口上监听。
- 注册teststtemplate和/或WebTestClient bean,以便在使用完全运行的web服务器的web测试中使用。
SpringBootTest配置项:
- value() 将属性配置加载到springContext中,定义的bean中使用@Value("${key1}")或者@Value("#{key1}")则可加载,配置格式value = {"key1=value1","key2=value2"}
- properties() 同上
- args() 应用参数格式 args = {"--arg1=v1","--arg2=v2"}) ,可通过@Value("${arg1}")获取和ApplicationArguments中获取,当properties和args配置了相同的key时,args优先级更高
- classes 指定类加载到ApplicationContext,便于快速测试。默认SpringBootTest会加载整个项目的Spring管理的bean
- webEnvironment 测试web运行环境,默认使用MOCK方式
- MOCK: 创建mockservlet环境如果
- RANDOM_PORT:随机port端口
- DEFINED_PORT:默认port端口
- NONE:
AbstractTestNGSpringContextTests
@RunWith(SpringRunner.class)将junit将测试类运行到SpringRunner中,但默认使用的junit,如果测试框架使用testng则该注解无法正常使用(Spring管理的对象无法被加载),需要测试类继承AbstractTestNGSpringContextTests,该类继承了Spring TestContext框架在TestNg环境。继承该类的子类的测试方法执行时会委托给run(IHookCallBack callBack, ITestResult testResult)执行
package com.tank.srpingboot;
import net.bytebuddy.asm.Advice;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.springframework.web.client.RestTemplate;
import org.testng.Assert;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
* @author tangkun
* @date 2021-04-04
*/
//@RunWith(SpringRunner.class)
@SpringBootTest(
webEnvironment= SpringBootTest.WebEnvironment.DEFINED_PORT,
value = {"pay.maxAmount=200","key3=200"},
args = {"--arg1=v1","--arg2=v2","--key3=300"}
)
public class OrderControllerTest extends AbstractTestNGSpringContextTests {
@Autowired
private RestTemplate restTemplate;
@Autowired
SysConfig sysConfig;
@Value("${arg1}")
private String arg1;
@Value("${key3}")
private int key3;
@Autowired
private ApplicationArguments args;
@Test public void testPayAmount() {
String userId = "0x1234";
String amount = "10";
String url = "http://localhost:8080/payAmount?userId=%s&amount=%s";
url = String.format(url,userId,amount);
ResponseEntity<String> result = restTemplate.getForEntity(url,String.class);
System.out.println(result);
Assert.assertEquals(sysConfig.getMaxAmount(),200);
}
@Test
public void getArgs(){
Assert.assertEquals("v1",arg1);
Assert.assertEquals("v1",args.getOptionValues("arg1").get(0));
}
@Test
public void getArgsAndProperties(){
Assert.assertEquals(300,key3);
}
}
IHookCallBack
AbstractTestNGSpringContextTests中run方法执行时,会调用IHookable的runTestMethod,该接口只能被TestNg实现。
public void run(IHookCallBack callBack, ITestResult testResult) {
Method testMethod = testResult.getMethod().getConstructorOrMethod().getMethod();
boolean beforeCallbacksExecuted = false;
try {
this.testContextManager.beforeTestExecution(this, testMethod);
beforeCallbacksExecuted = true;
}
catch (Throwable ex) {
this.testException = ex;
}
if (beforeCallbacksExecuted) {
//真正的测试方法会委托给callBack的runTestMethod执行
callBack.runTestMethod(testResult);
this.testException = getTestResultException(testResult);
}
try {
this.testContextManager.afterTestExecution(this, testMethod, this.testException);
}
catch (Throwable ex) {
if (this.testException == null) {
this.testException = ex;
}
}
if (this.testException != null) {
throwAsUncheckedException(this.testException);
}
}