您好,欢迎来到五一七教育网。
搜索
您的当前位置:首页springboot系列之集成测试(推荐)

springboot系列之集成测试(推荐)

来源:五一七教育网
springboot系列之集成测试(推荐)

如果希望很⽅便针对API进⾏测试,并且⽅便的集成到CI中验证每次的提交,那么spring boot⾃带的IT绝对是不⼆选择。迅速编写⼀个测试Case

@RunWith(SpringRunner.class)

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)@ActiveProfiles({Profiles.ENV_IT})public class DemoIntegrationTest{ @Autowired

private FooService fooService; @Test

public void test(){

System.out.println(\"tested\"); }}

其中 SpringBootTest 定义了跑IT时的⼀些配置,上述代码是⽤了随机端⼝,当然也可以预定义端⼝,像这样

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = {\"server.port=9990\

ActiveProfiles 强制使⽤了IT的Profile,从最佳实践上来说IT Profile所配置的数据库或者其他资源组件的地址,应该是与开发或者Staging环境隔离的。因为当⼀个IT跑完之后很多情况下我们需要清除测试数据。

你能够发现这样的Case可以使⽤ Autowired 注⼊任何想要的Service。这是因为spring将整个上下⽂都加载了起来,与实际运⾏的环境是⼀样的,包含了数据库,缓存等等组件。如果觉得测试时不需要全部的资源,那么在profile删除对应的配置就可以了。这就是⼀个完整的运⾏环境,唯⼀的区别是当⽤例跑完会⾃动shutdown。测试⼀个Rest API

强烈推荐⼀个库,加⼊到gradle中

testCompile 'io.rest-assured:rest-assured:3.0.3'

⽀持JsonPath,⼗分好⽤,具体⽂档戳 这⾥

@Sql(scripts = \"/testdata/users.sql\")@Test

public void test001Login() {

Stringusername=\"*************\"; String password = \"demo\";

JwtAuthenticationRequest request = new JwtAuthenticationRequest(username, password); Response response = given().contentType(ContentType.JSON).body(request) .when().post(\"/auth/login\").then() .statusCode(HttpStatus.OK.value()) .extract() .response();

assertThat(response.path(\"token\"), is(IsNull.notNullValue())); assertThat(response.path(\"expiration\"), is(IsNull.notNullValue()));}

@Sql ⽤于在测试前执⾏sql插⼊测试数据。注意 given().body() 中传⼊的是⼀个java对象 JwtAuthenticationRequest ,因为rest-assured会⾃动帮你⽤ jackson 将对象序列化成json字符串。当然也可以将转换好的json放到body,效果是⼀样的。返回结果被⼀个Response接住,之后就可以⽤JsonPath获取其中数据进⾏验证。当然还有⼀种更直观的办法,可以通过response.asString() 获取完整的response,再反序列化成java对象进⾏验证。

⾄此,最基本的IT就完成了。 在Jenkins增加⼀个step gradle test 就可以实现每次提交代码都进⾏⼀次测试。⼀些复杂的情况数据混杂

这是最容易发⽣,⼀个项⽬有很多dev,每个dev都会写⾃⼰的IT case,那么如果数据之间产⽣了影响怎么办。很容易理解,⽐如⼀个测试批量写的场景,最后验证⽅式是看写的数据量是不是10w⾏。那么另外⼀个dev写了其他的case恰好也新增了⼀条数据到这张表,结果变成了10w+1⾏,那么批量写的case就跑不过了。

为了杜绝这种情况,我们采⽤每次跑完⼀个测试Class就将数据清空。既然是基于类的操作,可以写⼀个基类解决。

@RunWith(SpringRunner.class)

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

@ActiveProfiles({Profiles.ENV_IT})

public abstract class BaseIntegrationTest { private static JdbcTemplate jdbcTemplate; @Autowired

public void setDataSource(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); }

@Value(\"${local.server.port}\") protected int port; @Before

public void setupEnv() { RestAssured.port = port;

RestAssured.basePath = \"/api\";

RestAssured.baseURI = \"http://localhost\";

RestAssured.config = RestAssured.config().httpClient(HttpClientConfig.httpClientConfig().httpMultipartMode(HttpMultipartMode.BROWSER_COMPATIBLE)); }

public void tearDownEnv() {

given().contentType(ContentType.JSON) .when().post(\"/auth/logout\"); }

@AfterClass

public static void cleanDB() throws SQLException {

Resource resource = new ClassPathResource(\"/testdata/CleanDB.sql\"); Connection connection = jdbcTemplate.getDataSource().getConnection(); ScriptUtils.executeSqlScript(connection, resource); connection.close(); }}

@AfterClass 中使⽤了jdbcTemplate执⾏了⼀个CleanDB.sql,通过这种⽅式清除所有测试数据。

@Value(\"${local.server.port}\") 也要提⼀下,因为端⼝是随机的,那么Rest-Assured不知道请求要发到losthost的哪个端⼝上,这⾥使⽤@Value 获取当前的端⼝号并设置到 RestAssured.port 就解决了这个问题。共有数据怎么处理

跑⼀次完整的IT,可能需要经历数⼗个Class,数百个method,那么如果⼀些数据是所有case都需要的,只有在所有case都跑完才需要清除怎么办?换句话说,这种数据清理不是基于 类 的,⽽是基于⼀次 运⾏ 。⽐如初始⽤户数据,城市库等等我们耍了个⼩聪明,借助了 flyway

@Configuration

@ConditionalOnClass({DataSource.class})public class UpgradeAutoConfiguration {

public static final String FLYWAY = \"flyway\"; @Bean(name = FLYWAY) @Profile({ENV_IT})

public UpgradeService cleanAndUpgradeService(DataSource dataSource) { UpgradeService upgradeService = new FlywayUpgradeService(dataSource); try {

upgradeService.cleanAndUpgrade(); } catch (Exception ex) {

LOGGER.error(\"Flyway failed!\ }

return upgradeService; }}

可以看到当Profile是IT的情况下, flyway 会drop掉所有表并重新依次执⾏每次的upgrade脚本,由此创建完整的数据表,当然都是空的。在项⽬的test路径下,增加⼀个版本极⼤的sql,这样就可以让 flyway 在最后插⼊共⽤的测试数据,例如src/test/resources/db/migration/V999.0.1__Insert_Users.sql ,完美的解决各种数据问题。⼩结

⽤Spring boot内置的测试服务可以很快速的验证API,我现在都不⽤把服务启动再通过⼈⼯页⾯点击来测试⾃⼰的API,直接与前端同事沟通好Request的格式,写个Case就可以验证。

当然这种⽅式也有⼀个不⾜就是不⽅便对系统进⾏压⼒测试,之前在公司的API测试⽤例都是Jmeter写的,做性能测试的时候会⽅便很多。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 517ttc.cn 版权所有 赣ICP备2024042791号-8

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务