如何使用 MongoDB 配置 TestContainer,併為資料訪問層和使用 MongoDB 的應用程式編寫整合測試。
TestContainer幫助我們在執行測試之前啟動容器,並透過在程式碼中定義它們來停止它們。
在本教程中,我們將瞭解如何使用 MongoDB配置TestContainers。接下來,我們將瞭解如何為測試建立基礎整合。最後,我們將學習如何使用 TestContainers 進行資料訪問層和應用程式與 MongoDB 的整合測試。
配置
為了在我們的測試中使用帶有 MongoDB 的 TestContainer,我們需要在具有測試範圍的pom.xml檔案中新增以下依賴項:
<dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers</artifactId> <version>1.18.3</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <version>1.18.3</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>mongodb</artifactId> <version>1.18.3</version> <scope>test</scope> </dependency>
|
我們有三個依賴項。第一個是核心依賴項,它提供 TestContainers 的主要功能,例如啟動和停止容器。下一個依賴項是 TestContainers 的 JUnit 5 擴充套件。最後一個依賴項是 TestContainers 的 MongoDB 模組。我們需要在我們的機器上安裝Docker來執行 MongoDB 容器。
建立模型
讓我們首先使用@Document註釋建立與Product表對應的實體:
@Document(collection = <font>"Product") public class Product { @Id private String id; private String name; private String description; private double price; // standard constructor, getters, setters<i> }
|
建立儲存庫
然後,我們將建立 從 MongoRepository擴充套件的ProductRepository 類:
@Repository public interface ProductRepository extends MongoRepository<Product, String> { Optional<Product> findByName(String name); }
|
建立 REST 控制器
最後,讓我們透過建立一個控制器來與儲存庫互動,從而公開 REST API :
@RestController @RequestMapping(<font>"/products") public class ProductController { private final ProductRepository productRepository; public ProductController(ProductRepository productRepository) { this.productRepository = productRepository; } @PostMapping public String createProduct(@RequestBody Product product) { return productRepository.save(product) .getId(); } @GetMapping("/{id}") public Product getProduct(@PathVariable String id) { return productRepository.findById(id) .orElseThrow(() -> new RuntimeException("Product not found")); } }
|
TestContainers MongoDB整合基礎
我們將建立一個抽象基類,該基類擴充套件到需要在執行測試之前和之後啟動和停止 MongoDB 容器的所有類:
@Testcontainers @SpringBootTest(classes = MongoDbTestContainersApplication.class) public abstract class AbstractBaseIntegrationTest { @Container static MongoDBContainer mongoDBContainer = new MongoDBContainer(<font>"mongo:7.0").withExposedPorts(27017); @DynamicPropertySource static void containersProperties(DynamicPropertyRegistry registry) { mongoDBContainer.start(); registry.add("spring.data.mongodb.host", mongoDBContainer::getHost); registry.add("spring.data.mongodb.port", mongoDBContainer::getFirstMappedPort); } }
|
我們新增了 @Testcontainers 註釋以在我們的測試中啟用TestContainers支援,並新增了@SpringBootTest註釋以啟動Spring Boot應用程式上下文。我們還定義了一個 MongoDB 容器欄位,該欄位使用mongo:7.0 Docker 映像啟動 MongoDB 容器並公開埠27017。@Container註釋在執行測試之前啟動 MongoDB 容器。
1. 資料訪問層整合測試
資料訪問層整合測試我們的應用程式與資料庫之間的互動。我們將為 MongoDB 資料庫建立一個簡單的資料訪問層併為其編寫整合測試。
讓我們建立擴充套件AbstractBaseIntegrationTest類的資料訪問整合測試類:
public class ProductDataLayerAccessIntegrationTest extends AbstractBaseIntegrationTest { @Autowired private ProductRepository productRepository; <font>// ..<i> }
|
現在,我們可以為資料訪問層編寫整合測試:@Test public void givenProductRepository_whenSaveAndRetrieveProduct_thenOK() { Product product = new Product(<font>"Milk", "1L Milk", 10); Product createdProduct = productRepository.save(product); Optional<Product> optionalProduct = productRepository.findById(createdProduct.getId()); assertThat(optionalProduct.isPresent()).isTrue(); Product retrievedProduct = optionalProduct.get(); assertThat(retrievedProduct.getId()).isEqualTo(product.getId()); } @Test public void givenProductRepository_whenFindByName_thenOK() { Product product = new Product("Apple", "Fruit", 10); Product createdProduct = productRepository.save(product); Optional<Product> optionalProduct = productRepository.findByName(createdProduct.getName()); assertThat(optionalProduct.isPresent()).isTrue(); Product retrievedProduct = optionalProduct.get(); assertThat(retrievedProduct.getId()).isEqualTo(product.getId()); }
|
我們建立了兩個場景:第一個場景儲存並檢索產品,第二個場景按名稱查詢產品。兩個測試都與 TestContainers 啟動的 MongoDB 資料庫進行互動。2. 應用程式整合測試
應用程式整合測試用於測試不同應用程式元件之間的互動。我們將建立一個使用我們之前建立的資料訪問層的簡單應用程式,併為其編寫整合測試。
讓我們建立擴充套件AbstractBaseIntegrationTest類的應用程式整合測試類:
@AutoConfigureMockMvc public class ProductIntegrationTest extends AbstractBaseIntegrationTest { @Autowired private MockMvc mvc; private ObjectMapper objectMapper = new ObjectMapper(); <font>// ..<i> }
|
我們需要@AutoConfigureMockMvc註釋來在我們的測試中啟用MockMvc支援,並需要MockMvc欄位對我們的應用程式執行 HTTP 請求。現在,我們可以為我們的應用程式編寫整合測試:
@Test public void givenProduct_whenSave_thenGetProduct() throws Exception { MvcResult mvcResult = mvc.perform(post(<font>"/products").contentType("application/json") .content(objectMapper.writeValueAsString(new Product("Banana", "Fruit", 10)))) .andExpect(status().isOk()) .andReturn(); String productId = mvcResult.getResponse() .getContentAsString(); mvc.perform(get("/products/" + productId)) .andExpect(status().isOk()); }
|
我們開發了一個測試來儲存產品,然後使用 HTTP 檢索它。此過程涉及將資料儲存在 MongoDB 資料庫中,該資料庫由 TestContainers 初始化。