如何測試簡單的 Spring Boot 應用程式

我們有一個示例 Spring 啟動應用程式,它將使用者資料儲存在 MongoDB 中,我們使用 Rest 服務來檢索資料

首先是域類,即 POJO

@Document
public class User{
    @Id
    private String id;

    private String name;

}

基於 Spring Data MongoDB 的相應儲存庫

public interface UserRepository extends MongoRepository<User, String> {
}

那我們的使用者控制器

@RestController
class UserController {
 
    @Autowired
    private UserRepository repository;
 
    @RequestMapping("/users")
    List<User> users() {
        return repository.findAll();
    }
 
    @RequestMapping(value = "/Users/{id}", method = RequestMethod.DELETE)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    void delete(@PathVariable("id") String id) {
        repository.delete(id);
    }
 
    // more controller methods
}

最後是我們的 Spring Boot 應用程式

@SpringBootApplication
public class Application {
    public static void main(String args[]){
     SpringApplication.run(Application.class, args);
    }
}

如果,讓我們說 John Cena,The Rock 和 TripleHHH 是資料庫中唯一的三個使用者,對/ users 的請求會給出以下響應:

$ curl localhost:8080/users
[{"name":"John Cena","id":"1"},{"name":"The Rock","id":"2"},{"name":"TripleHHH","id":"3"}]

現在要測試程式碼,我們將驗證應用程式是否正常工作

@RunWith(SpringJUnit4ClassRunner.class)   // 1
@SpringApplicationConfiguration(classes = Application.class)   // 2
@WebAppConfiguration   // 3
@IntegrationTest("server.port:0")   // 4
public class UserControllerTest {

    @Autowired   // 5
    UserRepository repository;

    User cena;
    User rock;
    User tripleHHH;

    @Value("${local.server.port}")   // 6
    int port;

    @Before
    public void setUp() {
        // 7
        cena = new User("John Cena");
        rock = new User("The Rock");
        tripleHHH = new User("TripleHH");

        // 8
        repository.deleteAll();
        repository.save(Arrays.asList(cena, rock, tripleHHH));

        // 9
        RestAssured.port = port;
    }

    // 10
    @Test
    public void testFetchCena() {
        String cenaId = cena.getId();

        when().
                get("/Users/{id}", cenaId).
        then().
                statusCode(HttpStatus.SC_OK).
                body("name", Matchers.is("John Cena")).
                body("id", Matchers.is(cenaId));
    }

    @Test
    public void testFetchAll() {
        when().
                get("/users").
        then().
                statusCode(HttpStatus.SC_OK).
                body("name", Matchers.hasItems("John Cena", "The Rock", "TripleHHH"));
    }

    @Test
    public void testDeletetripleHHH() {
        String tripleHHHId = tripleHHH.getId();

        when()
                .delete("/Users/{id}", tripleHHHId).
        then().
                statusCode(HttpStatus.SC_NO_CONTENT);
    }
}

說明

  1. 像任何其他基於 Spring 的測試一樣,我們需要 SpringJUnit4ClassRunner 以便建立應用程式上下文。
  2. @SpringApplicationConfiguration 註釋類似於 @ContextConfiguration 註釋,因為它用於指定應在測試中使用的應用程式上下文。此外,它還將觸發讀取 Spring Boot 特定配置,屬性等的邏輯。
  3. @WebAppConfiguration 必須存在才能告訴 Spring 應該載入 WebApplicationContext 進行測試。它還提供了一個屬性,用於指定 Web 應用程式根目錄的路徑。
  4. @IntegrationTest 用於告訴 Spring Boot 應該啟動嵌入式 Web 伺服器。通過提供冒號或等號分隔的名稱 - 值對,可以覆蓋任何環境變數。在此示例中,server.port:0 將覆蓋伺服器的預設埠設定。通常,伺服器將開始使用指定的埠號,但值 0 具有特殊含義。當指定為 0 時,它告訴 Spring Boot 掃描主機環境中的埠並在隨機可用埠上啟動伺服器。如果我們在開發機器上佔用不同埠的不同服務以及可能與應用程式埠發生衝突的構建伺服器,那麼這很有用,在這種情況下應用程式將無法啟動。其次,如果我們使用不同的應用程式上下文建立多個整合測試,
  5. 我們可以訪問應用程式上下文,並可以使用自動裝配來注入任何 Spring bean。
  6. @Value("${local.server.port}”) 將被解析為使用的實際埠號。
  7. 我們建立了一些可用於驗證的實體。
  8. 清除 MongoDB 資料庫併為每個測試重新初始化,以便我們始終針對已知狀態進行驗證。由於未定義測試的順序,因此如果 testFetchAll() 測試在 testDeletetripleHHH() 測試之後執行,則測試失敗的可能性很小。
  9. 我們指示 Rest Assured 使用正確的埠。它是一個開源專案,提供用於測試 restful 服務的 Java DSL
  10. 測試通過使用 Rest Assured 實現。我們可以使用 TestRestTemplate 或任何其他 http 客戶端來實現測試,但我使用 Rest Assured,因為我們可以使用 RestDocs 編寫簡明的文件