日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Spring Boot web項目的TDD流程

瀏覽:20日期:2023-07-13 09:34:35
目錄概述1 技術工具2 構建Spring Boot工程3 開始編寫測試和代碼1 Controller2 Service3 Repository4 總結概述

測試驅動開發可以分為三個周期,周而復始,紅燈-綠燈-重構。由以下幾個步驟構成:

編寫測試 運行所有測試 編寫代碼 運行所有測試 重構 運行所有測試

一開始編寫測試,肯定通不過,紅燈狀態,進行代碼編寫,然后運行測試,測試通不過,測試通過,即變成綠燈。

測試不通過,或者需要重構代碼,再次運行所有測試代碼...

接下來通過一個簡單的,一個RESTful請求的Spring boot web項目,演示和說明TDD的過程。

這個功能大致是這樣的,一個simple元素有id和desc兩個屬性

用戶發送GET請求http接口 http://localhost:8080/simples 返回所有的simple元素的json數組

1 技術工具 JDK8+ Spring Boot 2.1+ maven or Gradle JPA JUnit 5+ Mockito Hamcrest

一個常見的RESTful請求處理的MVC架構:

用戶訪問http url 通過Controller層接口 Controller層調用Service的實現 Service接口通過Repsoitory層訪問數據庫,并最終返回數據給用戶 2 構建Spring Boot工程

構建一個Spring Boot Maven工程,并添加所需的依賴

參考依賴如下

<properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.3.7.RELEASE</spring-boot.version> </properties> <dependencies><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions><exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId></exclusion> </exclusions></dependency> </dependencies> <dependencyManagement><dependencies> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope> </dependency></dependencies> </dependencyManagement>3 開始編寫測試和代碼1 Controller

首先編寫測試Controller層的測試,test代碼區創建一個測試類,SimpleControllerTest

添加兩個注解 @ExtendWith和@WebMvcTest。

然后添加一個MockMvc對象,用來模擬mvc的請求。單元測試中,每個模塊應當獨立的測試,實際調用鏈中,Controller依賴Service層,因為當前測的是Controller層,對于Service層的代碼則進行mock,這可以使用一個注解

@MockBean

整個代碼如下

@ExtendWith({SpringExtension.class})@WebMvcTestpublic class SimpleControllerTest { @Autowired MockMvc mockMvc; @MockBean private SimpleService simpleService;}

SimpleService不存在,編譯不通過,紅燈,則創建它。

如是創建一個SimpleService作為Service層的Spring bean。

@Servicepublic class SimpleService {}

然后編寫請求/simples http請求的測試代碼

@Test void testFindAllSimples() throws Exception {List<Simple> simpleList = new ArrayList<>();simpleList.add(new Simple(1L,'one'));simpleList.add(new Simple(2L,'two'));when(simpleService.findAll()).thenReturn(simpleList);mockMvc.perform(MockMvcRequestBuilders.get('/simples').contentType(MediaType.APPLICATION_JSON)).andExpect(jsonPath('$', hasSize(2))).andDo(print()); }

when then結構來自Mockito框架,when表示了執行的條件,then用于執行驗證,這里的操作對simpleService.findAll方法結果進行了mock,這里 在這一層不需關心的simpleService的真實實現。后面perform方法 mock了 /simples的請求。

這里報錯,紅燈,接下來編寫Simple類的實現。

@Entitypublic class Simple { private Long id; private String desc;public Simple(String desc) {this.desc = desc; } }

因為simpleService.findAll方法未定義,所以還是報錯的,紅燈。接下來保持簡單,給SimpleService創建一個findAll方法。

public List<Simple> findAll() {return new ArrayList<>(); }

編譯問題都解決了,下面開始運行測試代碼。

報錯,

java.lang.AssertionError: No value at JSON path “$”

還是紅燈,這是因為我們mock的perform 沒有存在。接下來創建一個SimpleController類作為RestController,并編寫/simples請求的接口。

@RestControllerpublic class SimpleController { @Autowired private SimpleService simpleService; @GetMapping('/simples') public ResponseEntity<List<Simple>> getAllSimples() {return new ResponseEntity<>(simpleService.findAll(), HttpStatus.OK); }}

再次運行測試用例,測試都通過了,綠燈。

2 Service

接下來讓我們關注Service層的代碼測試,test代碼區創建一個SimpleServiceTest類。該類對下一層Repository依賴,同樣的,創建一個Repository的mock對象。

@SpringBootTestpublic class SimpleServiceTest { @MockBean private SimpleRepository simpleRepository;}

編譯報錯,紅燈,需要創建一個SimpleRepository。

@Repositorypublic interface SimpleRepository extends JpaRepository<Simple,Long> {}

以上,創建SimpleRepository作為實體Simple類對象的JPA存儲服務。

編寫測試代碼

@Test void testFindAll() {Simple simple = new Simple('one');simpleRepository.save(simple);SimpleService simpleService = new SimpleService(simpleRepository);List<Simple> simples = simpleService.findAll();Simple entity = simples.get(simples.size() - 1);assertEquals(simple.getDesc(),entity.getDesc());assertEquals(simple.getId(),entity.getId()); }

繼續解決編譯報錯的問題,SimpleService沒有構造方法。添加Repository 并注入bean。

@Servicepublic class SimpleService { private SimpleRepository simpleRepository; public SimpleService(SimpleRepository simpleRepository) {this.simpleRepository = simpleRepository; } public List<Simple> findAll() {return new ArrayList<>(); }}

這里插播一個題外話,為啥Spring推薦通過構造方法的方式注入bean, 方便編寫可測試代碼是個重要原因。

運行測試用例,會繼續報錯,這里是因為JPA hibernate沒有和實體類對象交互,需要添加主鍵注解,默認構造函數 getter/setter 重新編寫實體類的代碼。

@Entitypublic class Simple { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String desc; public Simple() { } public Simple(String desc) {this.desc = desc; } // 省略 getter/setter ... }

修改完畢之后 運行測試用例 依然失敗,findAll方法測試未通過,修改SimpleService的findAll方法,調用 jpa repository的findAll方法

public List<Simple> findAll() {return simpleRepository.findAll(); }

現在再次運行測試用例,測試通過。

3 Repository

前面已經通過了TDD去實現Controller層和Service層的代碼,理論上Repository實現了JPA的接口,我們沒有做任何代碼的編寫,應該不需要進行測試,但是我們不確定數據是否通過數據庫進行了存儲和查詢。為了保證數據庫存儲,將真正的JPA respoitory實例注入的Service對象中。修改@MockBean 為@Autowired。

@SpringBootTestpublic class SimpleServiceTest { @Autowired private SimpleRepository simpleRepository; @Test void testFindAll() {Simple simple = new Simple('one');simpleRepository.save(simple);SimpleService simpleService = new SimpleService(simpleRepository);List<Simple> simpleEntities = simpleService.findAll();Simple entity = simpleEntities.get(simpleEntities.size() - 1);assertEquals(simple.getDesc(),entity.getDesc());assertEquals(simple.getId(),entity.getId()); }}

創建H2 database配置。

classpath下 創建schema.sql和data.sql,創建表和插入一點數據。

#************H2 Begin****************#創建表的MySql語句位置spring.datasource.schema=classpath:schema.sql#插入數據的MySql語句的位置spring.datasource.data=classpath:data.sql# 禁止自動根據entity創建表結構,表結構由schema.sql控制spring.jpa.hibernate.ddl-auto=nonespring.jpa.show-sql=true

schema.sql

DROP TABLE IF EXISTS simple;CREATE TABLE `simple` ( id BIGINT(20) auto_increment, desc varchar(255));

data.sql

INSERT INTO `simple`(`desc`) VALUES (’test1’);INSERT INTO `simple`(`desc`) VALUES (’test2’);

繼續運行測試用例,所有用例都測試通過,瀏覽器直接訪問localhost:8080/simples

返回data.sql插入的數據

[ {'id': 1,'desc': 'test1'},{'id': 2,'desc': 'test2'}]4 總結

以上是一個完整的TDD開發流程的演示,每一個模塊的測試具備獨立性,當前模塊中,可以mock其他模塊的數據。關于測試用例的結構,遵循的是AAA模式。

Arrange: 單元測試的第一步,需要進行必要的測試設置,譬如創建目標類對象,必要時,創建mock對象和其他變量初始化等等 Action: 調用要測試的目標方法 Assert: 單元測試的最后異步,檢查并驗證結果與預期的結果是否一致。

以上就是Spring Boot web項目的TDD流程的詳細內容,更多關于Spring Boot web項目TDD的資料請關注好吧啦網其它相關文章!

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
99精品美女| 日韩精品中文字幕一区二区| 国产精品夜夜夜| 日韩三区四区| 日本午夜精品一区二区三区电影| 国产一级一区二区| 性欧美69xoxoxoxo| 日韩视频一区| 午夜在线精品偷拍| 亚洲精品看片| 国产欧美日韩一区二区三区四区| 国产精品久一| 国产一二在线播放| 欧美99久久| 蜜桃视频第一区免费观看| 综合欧美精品| 国产午夜久久av| 福利一区二区免费视频 | 91久久在线| 国产视频亚洲| 日韩精品乱码av一区二区| 国产欧美日本| www.51av欧美视频| 欧美高清一区| 日韩欧美2区| 国产a亚洲精品| 欧美日韩四区| 日本特黄久久久高潮| 老牛国内精品亚洲成av人片 | bbw在线视频| re久久精品视频| 亚洲+小说+欧美+激情+另类| 亚洲va久久久噜噜噜久久| 国产精品一区二区精品视频观看| 亚洲精品**中文毛片| av亚洲在线观看| 91麻豆精品| 久久精品动漫| 日韩高清电影免费| 成人精品天堂一区二区三区| 日韩专区在线视频| 美女性感视频久久| 在线国产一区二区| 国产调教一区二区三区| se01亚洲视频 | 国产h片在线观看| 日韩一区二区免费看| 亚洲精品乱码日韩| 精品国产网站| 日韩精品一级中文字幕精品视频免费观看| 国产伦精品一区二区三区视频| 日韩欧美在线中字| 婷婷综合成人| 韩国三级一区| 奇米色欧美一区二区三区| 欧美天堂视频| 日韩中出av| 成人美女视频| 亚洲a级精品| 激情综合网址| 国产精品v日韩精品v欧美精品网站| 99久久夜色精品国产亚洲狼| 国产日韩在线观看视频| 99久久亚洲精品蜜臀| 国产探花在线精品| 1024精品久久久久久久久| 国产欧美一级| 久久最新视频| 色爱综合av| 国产伦精品一区二区三区千人斩| 伊人久久成人| 欧美精品99| 久久成人亚洲| 日韩欧美中文| 国产精品欧美在线观看| 国产美女精品| 成人午夜精品| 久久三级毛片| 日韩国产欧美在线视频| 亚洲欧洲午夜| 肉色欧美久久久久久久免费看| 国产亚洲观看| 综合欧美亚洲| 黄色亚洲在线| 日本高清不卡一区二区三区视频| 国产精品美女久久久久久不卡| 91久久视频| 日韩免费在线| 成人国产精品一区二区网站| 欧美日一区二区在线观看| 亚洲一区日本| 女人av一区| 日韩天堂在线| 国产一区二区三区不卡视频网站 | 久久久国产精品入口麻豆| 免费日本视频一区| 欧美福利一区| 欧美亚洲在线日韩| 欧美日韩视频网站| 黑人精品一区| 精品久久91| 麻豆91精品91久久久的内涵| 久久国产精品免费精品3p| 亚洲婷婷丁香| 蜜桃视频免费观看一区| 国产视频一区在线观看一区免费| 91精品一区二区三区综合| 五月天av在线| 日韩毛片视频| 成午夜精品一区二区三区软件| 久久不卡日韩美女| 国产激情久久| 国产精品mm| 欧美激情99| 麻豆精品在线| 久久97视频| 国产精品成久久久久| 麻豆视频久久| 国产一区二区三区久久| 国产福利91精品一区二区| 精品久久精品| 国产网站在线| 久久久久久久久久久9不雅视频| 亚洲天堂免费电影| 97国产精品| 日韩欧美一区免费| 伊人久久大香线蕉av不卡| 欧美不卡高清| 六月婷婷一区| 日韩一区中文| 国产精品一区二区中文字幕| 国产精品调教| 成人日韩av| 日韩国产一区二区| 国产精品av久久久久久麻豆网| 不卡中文字幕| 亚洲精一区二区三区| 青青草伊人久久| 麻豆91精品91久久久的内涵| 国产一区二区三区日韩精品| av资源中文在线| 久久亚洲国产| 日韩中文字幕91| 国产日韩欧美在线播放不卡| 精品香蕉视频| 人人精品亚洲| 久久国产精品99国产| 亚洲精品一二三**| 欧美日韩国产一区二区在线观看| 国产精品极品在线观看| 久久精品国产成人一区二区三区| 亚洲午夜天堂| 国产一级一区二区| 欧美亚洲一区二区三区| 麻豆91精品视频| 岛国av在线网站| aa国产精品| 国产欧美自拍一区| 成人片免费看| 久久国产精品久久w女人spa| 欧美日韩1区| 欧美三级精品| 亚洲小说春色综合另类电影| 国产精品亚洲四区在线观看| 日韩电影免费在线观看| 老牛国产精品一区的观看方式| 青青草视频一区| 色偷偷偷在线视频播放| 国产麻豆综合| 欧美精品97| 久久美女性网| 日韩精品成人在线观看| 中文字幕在线视频网站| 在线免费观看亚洲| 国产精品精品| 亚洲精品乱码久久久久久蜜桃麻豆| 毛片不卡一区二区| 亚洲一区欧美激情| 精品深夜福利视频| 先锋影音久久久| 久久免费精品| 日韩中文字幕av电影| 激情中国色综合| 视频一区欧美日韩| 国产a亚洲精品| 亚洲一区二区三区免费在线观看| 国产日韩欧美三区| 在线亚洲观看| 麻豆成全视频免费观看在线看| 在线日韩成人| 欧美香蕉视频| 国产毛片精品久久| 影音先锋国产精品| 成人黄色av| 日本精品国产| 国产精品av久久久久久麻豆网| 国产激情一区| 综合国产视频| 精品一区在线| 91视频一区|