這篇文章主要介紹“spring boot集成測(cè)試的方法”,在日常操作中,相信很多人在spring boot集成測(cè)試的方法問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”spring boot集成測(cè)試的方法”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
站在用戶(hù)的角度思考問(wèn)題,與客戶(hù)深入溝通,找到金川網(wǎng)站設(shè)計(jì)與金川網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶(hù)體驗(yàn)好的作品,建站類(lèi)型包括:網(wǎng)站設(shè)計(jì)制作、做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名申請(qǐng)、網(wǎng)頁(yè)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋金川地區(qū)。
如果希望很方便針對(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ù)定義端口,像這樣
1
@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")
@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用于在測(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è)stepgradle 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都跑完才需要清除怎么辦?換句話(huà)說(shuō),這種數(shù)據(jù)清理不是基于類(lèi)的,而是基于一次運(yùn)行。比如初始用戶(hù)數(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)題。
到此,關(guān)于“spring boot集成測(cè)試的方法”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
分享文章:springboot集成測(cè)試的方法
網(wǎng)址分享:http://chinadenli.net/article16/pddsdg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、全網(wǎng)營(yíng)銷(xiāo)推廣、網(wǎng)站維護(hù)、微信小程序、定制開(kāi)發(fā)、響應(yīng)式網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)