国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 開(kāi)發(fā) > Java > 正文

spring boot系列之集成測(cè)試(推薦)

2024-07-14 08:40:06
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

如果希望很方便針對(duì)API進(jìn)行測(cè)試,并且方便的集成到CI中驗(yàn)證每次的提交,那么spring boot自帶的IT絕對(duì)是不二選擇。

迅速編寫(xiě)一個(gè)測(cè)試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時(shí)的一些配置,上述代碼是用了隨機(jī)端口,當(dāng)然也可以預(yù)定義端口,像這樣

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

ActiveProfiles 強(qiáng)制使用了IT的Profile,從最佳實(shí)踐上來(lái)說(shuō)IT Profile所配置的數(shù)據(jù)庫(kù)或者其他資源組件的地址,應(yīng)該是與開(kāi)發(fā)或者Staging環(huán)境隔離的。因?yàn)楫?dāng)一個(gè)IT跑完之后很多情況下我們需要清除測(cè)試數(shù)據(jù)。

你能夠發(fā)現(xiàn)這樣的Case可以使用 Autowired 注入任何想要的Service。這是因?yàn)閟pring將整個(gè)上下文都加載了起來(lái),與實(shí)際運(yùn)行的環(huán)境是一樣的,包含了數(shù)據(jù)庫(kù),緩存等等組件。如果覺(jué)得測(cè)試時(shí)不需要全部的資源,那么在profile刪除對(duì)應(yīng)的配置就可以了。這就是一個(gè)完整的運(yùn)行環(huán)境,唯一的區(qū)別是當(dāng)用例跑完會(huì)自動(dòng)shutdown。

測(cè)試一個(gè)Rest API

強(qiáng)烈推薦一個(gè)庫(kù),加入到gradle中

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

支持JsonPath,十分好用,具體文檔戳 這里

@Sql(scripts = "/testdata/users.sql")@Testpublic void test001Login() {  String username = "demo@demo.com";  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 用于在測(cè)試前執(zhí)行sql插入測(cè)試數(shù)據(jù)。注意 given().body() 中傳入的是一個(gè)java對(duì)象 JwtAuthenticationRequest ,因?yàn)閞est-assured會(huì)自動(dòng)幫你用 jackson 將對(duì)象序列化成json字符串。當(dāng)然也可以將轉(zhuǎn)換好的json放到body,效果是一樣的。

返回結(jié)果被一個(gè)Response接住,之后就可以用JsonPath獲取其中數(shù)據(jù)進(jìn)行驗(yàn)證。當(dāng)然還有一種更直觀的辦法,可以通過(guò) response.asString() 獲取完整的response,再反序列化成java對(duì)象進(jìn)行驗(yàn)證。

至此,最基本的IT就完成了。 在Jenkins增加一個(gè)step gradle test 就可以實(shí)現(xiàn)每次提交代碼都進(jìn)行一次測(cè)試。

一些復(fù)雜的情況

數(shù)據(jù)混雜

這是最容易發(fā)生,一個(gè)項(xiàng)目有很多dev,每個(gè)dev都會(huì)寫(xiě)自己的IT case,那么如果數(shù)據(jù)之間產(chǎn)生了影響怎么辦。很容易理解,比如一個(gè)測(cè)試批量寫(xiě)的場(chǎng)景,最后驗(yàn)證方式是看寫(xiě)的數(shù)據(jù)量是不是10w行。那么另外一個(gè)dev寫(xiě)了其他的case恰好也新增了一條數(shù)據(jù)到這張表,結(jié)果變成了10w+1行,那么批量寫(xiě)的case就跑不過(guò)了。

為了杜絕這種情況,我們采用每次跑完一個(gè)測(cè)試Class就將數(shù)據(jù)清空。既然是基于類(lèi)的操作,可以寫(xiě)一個(gè)基類(lèi)解決。

@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執(zhí)行了一個(gè)CleanDB.sql,通過(guò)這種方式清除所有測(cè)試數(shù)據(jù)。

@Value("${local.server.port}") 也要提一下,因?yàn)槎丝谑请S機(jī)的,那么Rest-Assured不知道請(qǐng)求要發(fā)到losthost的哪個(gè)端口上,這里使用 @Value 獲取當(dāng)前的端口號(hào)并設(shè)置到 RestAssured.port 就解決了這個(gè)問(wèn)題。

共有數(shù)據(jù)怎么處理

跑一次完整的IT,可能需要經(jīng)歷數(shù)十個(gè)Class,數(shù)百個(gè)method,那么如果一些數(shù)據(jù)是所有case都需要的,只有在所有case都跑完才需要清除怎么辦?換句話說(shuō),這種數(shù)據(jù)清理不是基于 類(lèi) 的,而是基于一次 運(yùn)行 。比如初始用戶數(shù)據(jù),城市庫(kù)等等

我們耍了個(gè)小聰明,借助了 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!", ex);    }    return upgradeService;  }}

可以看到當(dāng)Profile是IT的情況下, flyway 會(huì)drop掉所有表并重新依次執(zhí)行每次的upgrade腳本,由此創(chuàng)建完整的數(shù)據(jù)表,當(dāng)然都是空的。在項(xiàng)目的test路徑下,增加一個(gè)版本極大的sql,這樣就可以讓 flyway 在最后插入共用的測(cè)試數(shù)據(jù),例如 src/test/resources/db/migration/V999.0.1__Insert_Users.sql ,完美的解決各種數(shù)據(jù)問(wèn)題。

小結(jié)

用Spring boot內(nèi)置的測(cè)試服務(wù)可以很快速的驗(yàn)證API,我現(xiàn)在都不用把服務(wù)啟動(dòng)再通過(guò)人工頁(yè)面點(diǎn)擊來(lái)測(cè)試自己的API,直接與前端同事溝通好Request的格式,寫(xiě)個(gè)Case就可以驗(yàn)證。

當(dāng)然這種方式也有一個(gè)不足就是不方便對(duì)系統(tǒng)進(jìn)行壓力測(cè)試,之前在公司的API測(cè)試用例都是Jmeter寫(xiě)的,做性能測(cè)試的時(shí)候會(huì)方便很多。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到JAVA教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 汉阴县| 商城县| 南京市| 章丘市| 宁津县| 常山县| 滦南县| 灵寿县| 时尚| 玉林市| 呼和浩特市| 东台市| 新野县| 湘乡市| 沈丘县| 上饶市| 徐州市| 桃园市| 辉县市| 鄯善县| 珠海市| 毕节市| 漯河市| 开原市| 新化县| 崇信县| 肥乡县| 长海县| 乾安县| 永靖县| 青冈县| 澳门| 台中市| 常宁市| 儋州市| 北安市| 从江县| 南雄市| 梁河县| 赣州市| 灯塔市|