溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

spring boot集成測試的方法

發(fā)布時間:2022-03-14 16:13:45 來源:億速云 閱讀:554 作者:iii 欄目:web開發(fā)

這篇文章主要介紹“spring boot集成測試的方法”,在日常操作中,相信很多人在spring boot集成測試的方法問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”spring boot集成測試的方法”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

如果希望很方便針對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時的一些配置,上述代碼是用了隨機端口,當(dāng)然也可以預(yù)定義端口,像這樣

1

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

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

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

測試一個Rest API

強烈推薦一個庫,加入到gradle中

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

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

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

@Test

public 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用于在測試前執(zhí)行sql插入測試數(shù)據(jù)。注意given().body()中傳入的是一個java對象JwtAuthenticationRequest,因為rest-assured會自動幫你用jackson將對象序列化成json字符串。當(dāng)然也可以將轉(zhuǎn)換好的json放到body,效果是一樣的。

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

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

一些復(fù)雜的情況

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

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

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

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

@Value("${local.server.port}")也要提一下,因為端口是隨機的,那么Rest-Assured不知道請求要發(fā)到losthost的哪個端口上,這里使用@Value獲取當(dāng)前的端口號并設(shè)置到RestAssured.port就解決了這個問題。

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

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

我們耍了個小聰明,借助了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會drop掉所有表并重新依次執(zhí)行每次的upgrade腳本,由此創(chuàng)建完整的數(shù)據(jù)表,當(dāng)然都是空的。在項目的test路徑下,增加一個版本極大的sql,這樣就可以讓flyway在最后插入共用的測試數(shù)據(jù),例如src/test/resources/db/migration/V999.0.1__Insert_Users.sql ,完美的解決各種數(shù)據(jù)問題。

到此,關(guān)于“spring boot集成測試的方法”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI