iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 7
0
Software Development

30天從零開始 使用 Spring Boot 跟 Spring Cloud 建構完整微服務架構系列 第 7

Day 07 - 寫 SpringBoot 的 Unit test

在我們服務開發到一定階段後, 你就可以一邊開始寫測試案例了.
不管你公司有沒有規定要寫, 我覺得寫測試都是工程師對自己產出負責的態度與方式.

測試不會讓你完全沒有 bug 只是減少一些錯誤發生的機會,
也對日後要接手你專案的人幫助他測試改的到底對不對.

你寫了測試, 日後才有可能談所謂 CI CD DevOps 自動化.

你在外面也會聽到有些公司在說我們也要 CI CD 邁向 DevOps, 講了大半年都沒落地...
負能量專欄:實現才叫夢想,不然你都是幻想

從不起眼處扎根本事, 讓我們從測試開始吧

先看我們的 /test/resources/application.yml

spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE
    initialize: false
    sql-script-encoding: UTF-8
  jpa:
    hibernate:
      ddl-auto: create-drop
    database-platform: H2
    show-sql: true
    generate-ddl: false

上一篇多少都有提到就不重複介紹了

接下來我們的測試 BookApplicationTests.java

package com.example.book;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.*;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static junit.framework.TestCase.assertTrue;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = BookApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BookApplicationTests {

    @Autowired
    private BookRepository bookRepository;

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void testGetBook() {
        Book book = new Book();
        book.setName("被討厭的勇氣:自我啟發之父「阿德勒」的教導");
        book.setAuthor("岸見一郎");
        book = bookRepository.save(book);

        UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/api/v1/book/{bookid}");
        Map<String, Object> uriParams = new HashMap<String, Object>();
        uriParams.put("bookid", book.getBookid());

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        HttpEntity<Object> entity = new HttpEntity<>(headers);
        ResponseEntity<String> response = restTemplate.exchange(
                builder.buildAndExpand(uriParams).toUri().toString(),
                HttpMethod.GET, entity, String.class);
        assertTrue("testGetBook Fail:\n" + response.getBody(),
                response.getStatusCode().is2xxSuccessful());
    }

}

說明一下我們這樣測試是真的會啟動一個 H2 資料庫, 並不用額外去寫 mock 的代碼, 其實就是越接近真實越好.

webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT

這個呢, 是讓測試啟動的時候隨機去聽一個 port, 避免測試主機上大家都會去搶特定一個 port

你會想說測試時 port 是隨機...那要怎麼測勒?
我們用了這個 TestRestTemplate, 好像是比較後來 Spring 針對測試時的工具,
用這工具啊...就不用給完整 url , 給 uri 部分他就自己可以幫你打到正確的 port, 像下面這樣

UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/api/v1/book/{bookid}");

這樣寫測試方便簡單又接近真實資料庫狀況呢~~


上一篇
Day 06 - 將 Swagger 規格說明匯出成 PDF 文件
下一篇
Day 08 - 如何在 SpringBoot 中使用 Retry & Cache
系列文
30天從零開始 使用 Spring Boot 跟 Spring Cloud 建構完整微服務架構35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
netlabfox
iT邦新手 5 級 ‧ 2021-05-27 10:17:57
        Book book = new Book();
        book.setName("被討厭的勇氣:自我啟發之父「阿德勒」的教導");
        book.setAuthor("岸見一郎");
        book = bookRepository.save(book);

上面這段code沒給ID,會有產生問題

Sam iT邦新手 4 級 ‧ 2021-05-27 10:38:04 檢舉

範例是使用 DB 的 AUTO_INCREMENT 所以沒給ID也沒問題, 你如果不希望使用 DB 機制, 可以查查 UUID 或雪花算法之類的的機制來使用

netlabfox iT邦新手 5 級 ‧ 2021-05-27 13:45:34 檢舉

謝謝,後來發現是intellij Test預設用gradle,改成用IDE就沒有這個問題了

我要留言

立即登入留言