Skip to content

Improve tests #131

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
piomin opened this issue May 10, 2025 · 7 comments
Open

Improve tests #131

piomin opened this issue May 10, 2025 · 7 comments

Comments

@piomin
Copy link
Owner

piomin commented May 10, 2025

Maige find Spring Boot test classes in the code and improve those tests

@piomin
Copy link
Owner Author

piomin commented May 10, 2025

maige could you help with that?

@piomin
Copy link
Owner Author

piomin commented May 11, 2025

@coderabbitai find Spring Boot test classes in the code and improve those tests

Copy link
Contributor

coderabbitai bot commented May 11, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all test classes in the codebase
find . -type f -name "*Test*.java" | sort

Length of output: 557


🏁 Script executed:

#!/bin/bash
# Check the content of the first test file
cat ./account-service/src/test/java/pl/piomin/microservices/advanced/account/TestApplication.java
echo "=============================================="
# Check the content of the second test file
cat ./account-service/src/test/java/pl/piomin/microservices/advanced/account/repository/AccountRepositoryTest.java

Length of output: 2892


🏁 Script executed:

#!/bin/bash
# Check the content of the remaining test files
echo "============== CustomerControllerTests.java ================"
cat ./customer-service/src/test/java/pl/piomin/microservices/advanced/customer/CustomerControllerTests.java
echo "============== CustomerRepositoryTests.java ================"
cat ./customer-service/src/test/java/pl/piomin/microservices/advanced/customer/CustomerRepositoryTests.java
echo "============== ProductRepositoryTests.java ================"
cat ./product-service/src/test/java/pl/piomin/microservices/advanced/product/ProductRepositoryTests.java

Length of output: 8499


🏁 Script executed:

#!/bin/bash
# Let's check the structure of the services to understand the controllers and service layers

echo "======= ACCOUNT SERVICE STRUCTURE ======="
find ./account-service/src/main -type f -name "*.java" | sort

echo "======= CUSTOMER SERVICE STRUCTURE ======="
find ./customer-service/src/main -type f -name "*.java" | sort

echo "======= PRODUCT SERVICE STRUCTURE ======="
find ./product-service/src/main -type f -name "*.java" | sort

Length of output: 2242


🏁 Script executed:

#!/bin/bash
# Let's check the AccountController to understand what endpoints we should test
cat ./account-service/src/main/java/pl/piomin/microservices/advanced/account/api/AccountController.java

echo "======= CUSTOMER CONTROLLER ======="
cat ./customer-service/src/main/java/pl/piomin/microservices/advanced/customer/api/CustomerController.java

echo "======= PRODUCT CONTROLLER ======="
cat ./product-service/src/main/java/pl/piomin/microservices/advanced/product/api/ProductController.java

Length of output: 6907


flowchart TB
    A(["Improve Spring Boot Tests"])
    A --o B["1. Enhance Repository Tests"]
    A --o C["2. Add Controller Tests"]
    A --o D["3. Add Integration Tests"]
    
    B --o B1["Add edge cases & validation tests"]
    B --o B2["Add update/delete operation tests"]
    B --o B3["Improve assertions & test structure"]
    
    C --o C1["Create AccountController tests"]
    C --o C2["Complete CustomerController tests"]
    C --o C3["Create ProductController tests"]
    
    D --o D1["Test service-to-service communication"]
    D --o D2["Add proper mocking & error handling"]
    D --o D3["Test failure scenarios"]
Loading

@piomin I've analyzed the current test files in your codebase and have a plan to improve them. Here's what I found:

  1. Repository Tests: You have repository tests for Account, Customer, and Product services that use Testcontainers to test MongoDB interactions. These tests are basic and could be enhanced with more test cases and better assertions.

  2. Controller Tests: You have some controller tests (CustomerControllerTests) but they're incomplete, with commented-out tests. The AccountController and ProductController don't have dedicated test classes.

  3. Integration Tests: There's a TestApplication class that appears to be for integration testing, but it's not being used in comprehensive tests.

I've created a comprehensive plan for improving the tests, which includes:

  1. Enhancing Repository Tests:

    • Adding more test cases for edge scenarios
    • Adding update/delete operation tests
    • Improving assertions for better test quality
  2. Adding Controller Tests:

    • Creating tests for AccountController
    • Completing CustomerController tests
    • Creating tests for ProductController
  3. Adding Integration Tests:

    • Testing service-to-service communication
    • Adding proper mocking with Hoverfly
    • Testing failure scenarios

Another agent will come along to implement these changes. Would you like me to prioritize any specific area of testing first?


⏳ Preparing changes...

Copy link
Contributor

coderabbitai bot commented May 11, 2025

Caution

CodeRabbit did not find changes to make.

@piomin
Copy link
Owner Author

piomin commented May 12, 2025

@coderabbitai can you prepare a new PR with changes according to your comprehensive plan for improving the tests?

Copy link
Contributor

coderabbitai bot commented May 12, 2025

Tip

For best results, initiate chat on the files or code changes.

A summary of the edits CodeRabbit can apply:

AccountRepositoryTest.java will be enhanced with additional imports, constants, and new test methods for broader coverage and stronger assertions.

CustomerRepositoryTests.java will be enhanced with additional test methods, improved assertions, and better coverage.

AccountRepositoryTest.java will be enhanced with additional test coverage and stronger assertions.

CustomerRepositoryTests.java will be enhanced with additional test scenarios and stronger assertions.

ProductRepositoryTests.java will be enhanced with additional test scenarios and stronger assertions.

CustomerControllerTests.java will be updated to assert the addCustomerTest response and enable the findCustomerWithAccounts test.

AccountControllerTest.java will be created to cover all controller endpoints in account-service.

ProductControllerTest.java will be created to cover all controller endpoints in product-service with Hoverfly mocking.

AccountContainersConfiguration.java will be created to share Testcontainers setup in account-service.

CustomerContainersConfiguration.java will be created to share Testcontainers setup in customer-service.

ProductContainersConfiguration.java will be created to share Testcontainers setup in product-service.

Enhance AccountRepositoryTest.java with additional test cases and stronger assertions

Enhance CustomerRepositoryTests.java with additional test cases and stronger assertions

Enhance ProductRepositoryTests.java with additional test cases and stronger assertions

Create AccountControllerTest.java with full REST endpoint coverage for AccountController

Create ProductControllerTest.java with full REST endpoint & Hoverfly mocks for ProductController

Create reusable Testcontainers configuration for account-service

Create reusable Testcontainers configuration for customer-service

Create reusable Testcontainers configuration for product-service

AccountRepositoryTest.java will be enhanced with more test coverage and improved assertions.

CustomerRepositoryTests.java will be enhanced with more test coverage and improved assertions.

ProductRepositoryTests.java will be enhanced with more test coverage and improved assertions.

AccountControllerTest.java will be created to add comprehensive controller tests.

ProductControllerTest.java will be created to add comprehensive controller tests with Hoverfly mocking.

AccountContainersConfiguration.java will be created to centralize Testcontainers configuration for account-service.

CustomerContainersConfiguration.java will be created to centralize Testcontainers configuration for customer-service.

ProductContainersConfiguration.java will be created to centralize Testcontainers configuration for product-service.

ServiceIntegrationTests.java will be created to implement end-to-end integration scenarios across all microservices.

A plan of each step that CodeRabbit will take in order to execute the edits for each file (with inline rough draft snippets):

✏️ account-service/src/test/java/pl/piomin/microservices/advanced/account/repository/AccountRepositoryTest.java

After the existing imports, insert new imports for List, UUID, and the additional assertion methods. For example, immediately after the line import java.util.Optional; add:
```
import java.util.List;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;


---

After the line <code>static String id;</code> declare two constants for reuse:
      ```
static final String ACCOUNT_NUMBER = "12345678909";
static final String CUSTOMER_ID = "234353464576586464";

In testAddAccount, replace hard-coded values with the constants and add assertions for number, customerId, and balance. Change:
```
a.setNumber("12345678909");
a.setCustomerId("234353464576586464");
...
assertNotNull(a.getId());
id = a.getId();

      to:
      ```
a.setNumber(ACCOUNT_NUMBER);
a.setBalance(1232);
a.setCustomerId(CUSTOMER_ID);
a = repository.save(a);
assertNotNull(a);
assertNotNull(a.getId());
assertEquals(1232, a.getBalance());
assertEquals(ACCOUNT_NUMBER, a.getNumber());
assertEquals(CUSTOMER_ID, a.getCustomerId());
id = a.getId();

In testFindAccount, after assertTrue(optAcc.isPresent()); add:
```
Account account = optAcc.get();
assertEquals(id, account.getId());
assertEquals(ACCOUNT_NUMBER, account.getNumber());
assertEquals(CUSTOMER_ID, account.getCustomerId());
assertEquals(1232, account.getBalance());


---

In <code>testFindAccountByNumber</code>, use the constant and strengthen assertions. Replace:
      ```
Account a = repository.findByNumber("12345678909");
...
assertNotNull(a.getId());
  with:
  ```

Account a = repository.findByNumber(ACCOUNT_NUMBER);
assertNotNull(a);
assertNotNull(a.getId());
assertEquals(id, a.getId());
assertEquals(CUSTOMER_ID, a.getCustomerId());


---

Add a new test method <code>testFindAccountsByCustomerId</code> at Order(3):
      ```
@Test
@Order(3)
public void testFindAccountsByCustomerId() {
    List<Account> accounts = repository.findByCustomerId(CUSTOMER_ID);
    assertNotNull(accounts);
    assertFalse(accounts.isEmpty());
    assertEquals(1, accounts.size());
    assertEquals(id, accounts.get(0).getId());
    assertEquals(ACCOUNT_NUMBER, accounts.get(0).getNumber());
}

Add testUpdateAccountBalance at Order(4) to verify updating:
```
@test
@order(4)
public void testUpdateAccountBalance() {
Optional optAcc = repository.findById(id);
assertTrue(optAcc.isPresent());
Account account = optAcc.get();
int newBalance = 2500;
account.setBalance(newBalance);
Account updated = repository.save(account);
assertEquals(newBalance, updated.getBalance());
assertEquals(id, updated.getId());
assertEquals(ACCOUNT_NUMBER, updated.getNumber());
}


---

Add <code>testFindAllAccounts</code> at Order(5) to ensure findAll works:
      ```
@Test
@Order(5)
public void testFindAllAccounts() {
    List<Account> accounts = repository.findAll();
    assertNotNull(accounts);
    assertFalse(accounts.isEmpty());
}

Add testFindNonExistentAccount at Order(6) to cover negative scenarios:
```
@test
@order(6)
public void testFindNonExistentAccount() {
String randomId = UUID.randomUUID().toString();
Optional optAccount = repository.findById(randomId);
assertFalse(optAccount.isPresent());
Account nonExistentAccount = repository.findByNumber("non-existent-number");
assertEquals(null, nonExistentAccount);
}


</details>

<details>
<summary>✏️ customer-service/src/test/java/pl/piomin/microservices/advanced/customer/CustomerRepositoryTests.java</summary>

Add the missing imports. After the existing imports (around line 18), insert:
```java
import java.util.List;
import java.util.UUID;

Then after the static imports (around line 22), insert:

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

Define constants for the test data. Immediately after static String id; (around line 37), insert:

static final String CUSTOMER_NAME = "Test1";
static final String CUSTOMER_PESEL = "1234567890";

Update the existing testAddCustomer() to use the constants and add assertions for name, pesel, and type. Change:

c.setName("Test1");
c.setPesel("1234567890");

to

c.setName(CUSTOMER_NAME);
c.setPesel(CUSTOMER_PESEL);

and after saving add:

assertEquals(CUSTOMER_NAME, c.getName());
assertEquals(CUSTOMER_PESEL, c.getPesel());
assertEquals(CustomerType.INDIVIDUAL, c.getType());

Enhance the testFindCustomer() and testFindCustomerByPesel() methods to verify all fields. For example, in testFindCustomer() add:

Customer customer = optCus.get();
assertEquals(id, customer.getId());
assertEquals(CUSTOMER_NAME, customer.getName());
assertEquals(CUSTOMER_PESEL, customer.getPesel());
assertEquals(CustomerType.INDIVIDUAL, customer.getType());

And in testFindCustomerByPesel() add:

assertEquals(id, c.getId());
assertEquals(CUSTOMER_NAME, c.getName());
assertEquals(CustomerType.INDIVIDUAL, c.getType());

Add the following new test methods before the closing brace of the class (after line 68):

@Test
@Order(3)
public void testUpdateCustomer() {
    Optional<Customer> optCus = repository.findById(id);
    assertTrue(optCus.isPresent());
    Customer customer = optCus.get();
    // Update name
    String newName = "Updated Name";
    customer.setName(newName);
    Customer updated = repository.save(customer);
    assertEquals(newName, updated.getName());
    assertEquals(id, updated.getId());
    assertEquals(CUSTOMER_PESEL, updated.getPesel());
    assertEquals(CustomerType.INDIVIDUAL, updated.getType());
}

@Test
@Order(4)
public void testFindAllCustomers() {
    List<Customer> customers = repository.findAll();
    assertNotNull(customers);
    assertFalse(customers.isEmpty());
    assertTrue(customers.size() >= 1);
}

@Test
@Order(5)
public void testAddCorporateCustomer() {
    Customer c = new Customer();
    c.setName("Corporate Inc.");
    c.setPesel("9876543210");
    c.setType(CustomerType.CORPORATE);
    c = repository.save(c);
    assertNotNull(c);
    assertNotNull(c.getId());
    assertEquals("Corporate Inc.", c.getName());
    assertEquals("9876543210", c.getPesel());
    assertEquals(CustomerType.CORPORATE, c.getType());
}

@Test
@Order(6)
public void testFindNonExistentCustomer() {
    String randomId = UUID.randomUUID().toString();
    Optional<Customer> optCustomer = repository.findById(randomId);
    assertFalse(optCustomer.isPresent());
    Customer nonExistentCustomer = repository.findByPesel("non-existent-pesel");
    assertEquals(null, nonExistentCustomer);
}

Run the updated test suite to verify that all tests compile and pass against the Testcontainer-backed MongoDB instance.

✏️ product-service/src/test/java/pl/piomin/microservices/advanced/product/ProductRepositoryTests.java

After existing imports add:

import java.util.List;
import java.util.UUID;

After static String id;, add:

static final String ACCOUNT_ID   = "123";
static final String CUSTOMER_ID  = "123";
static final int    INITIAL_BALANCE = 10000;

In testAddProduct, replace literals with constants and add assertions for all fields:

-   p.setAccountId("123");
-   p.setCustomerId("123");
+   p.setAccountId(ACCOUNT_ID);
+   p.setCustomerId(CUSTOMER_ID);
    p.setType(ProductType.CREDIT);
-   p.setBalance(10000);
+   p.setBalance(INITIAL_BALANCE);
    p.setDateOfStart(LocalDate.now());
    p = repository.save(p);
    assertNotNull(p);
    assertNotNull(p.getId());
+   assertEquals(ACCOUNT_ID, p.getAccountId());
+   assertEquals(CUSTOMER_ID, p.getCustomerId());
+   assertEquals(ProductType.CREDIT, p.getType());
+   assertEquals(INITIAL_BALANCE, p.getBalance());
+   assertNotNull(p.getDateOfStart());
    id = p.getId();

In testFindProduct, unpack and assert all fields:

Product product = optCus.get();
assertEquals(id, product.getId());
assertEquals(ACCOUNT_ID, product.getAccountId());
assertEquals(CUSTOMER_ID, product.getCustomerId());
assertEquals(ProductType.CREDIT, product.getType());
assertEquals(INITIAL_BALANCE, product.getBalance());

In testFindProductByAccountId, use the constant and add assertions:

-   Product p = repository.findByAccountId("123");
+   Product p = repository.findByAccountId(ACCOUNT_ID);
    assertNotNull(p);
    assertNotNull(p.getId());
+   assertEquals(id, p.getId());
+   assertEquals(CUSTOMER_ID, p.getCustomerId());
+   assertEquals(ProductType.CREDIT, p.getType());
+   assertEquals(INITIAL_BALANCE, p.getBalance());

Append these new test methods after the existing ones:

@Test
@Order(3)
public void testUpdateProductBalance() {
    Product product = repository.findById(id).get();
    int newBalance = 15000;
    product.setBalance(newBalance);
    Product updated = repository.save(product);
    assertEquals(newBalance, updated.getBalance());
    assertEquals(id, updated.getId());
    assertEquals(ACCOUNT_ID, updated.getAccountId());
    assertEquals(ProductType.CREDIT, updated.getType());
}

@Test
@Order(4)
public void testFindAllProducts() {
    List<Product> products = repository.findAll();
    assertNotNull(products);
    assertFalse(products.isEmpty());
    assertTrue(products.size() >= 1);
}

@Test
@Order(5)
public void testAddDebitProduct() {
    Product p = new Product();
    p.setAccountId("456");
    p.setCustomerId("456");
    p.setType(ProductType.DEBIT);
    p.setBalance(5000);
    p.setDateOfStart(LocalDate.now());
    p = repository.save(p);
    assertNotNull(p);
    assertNotNull(p.getId());
    assertEquals("456", p.getAccountId());
    assertEquals("456", p.getCustomerId());
    assertEquals(ProductType.DEBIT, p.getType());
    assertEquals(5000, p.getBalance());
}

@Test
@Order(6)
public void testFindNonExistentProduct() {
    String randomId = UUID.randomUUID().toString();
    Optional<Product> optProduct = repository.findById(randomId);
    assertFalse(optProduct.isPresent());
    Product nonExistentProduct = repository.findByAccountId("non-existent-account");
    assertNull(nonExistentProduct);
}
✏️ customer-service/src/test/java/pl/piomin/microservices/advanced/customer/CustomerControllerTests.java

Add these imports after existing ones:

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import org.junit.jupiter.api.Test;

After @Autowired TestRestTemplate template; add constants and reuse id:

static String id;
static final String CUSTOMER_PESSEL = "1234567890";
static final String CUSTOMER_NAME  = "Jan Testowy";

In addCustomerTest, assert the response and set id:

-   c = template.postForObject("/customers", c, Customer.class);
+   Customer created = template.postForObject("/customers", c, Customer.class);
+   assertNotNull(created);
+   assertNotNull(created.getId());
+   assertEquals(CUSTOMER_PESSEL, created.getPesel());
+   assertEquals(CUSTOMER_NAME, created.getName());
+   assertEquals(CustomerType.INDIVIDUAL, created.getType());
+   id = created.getId();

Uncomment and update the second test method to enable it:

-//    @Test
-//    @Order(2)
-public void findCustomerWithAccounts(Hoverfly hoverfly) {
+    @Test
+    @Order(2)
+    public void findCustomerWithAccounts(Hoverfly hoverfly) {
         hoverfly.simulate(
             dsl(service("http://account-service")
                     .get(startsWith("/accounts/customer"))
                     .willReturn(success("[{\"id\":\"1\",\"number\":\"1234567890\"}]", "application/json"))));
-        Customer c = template.getForObject("/customers/pesel/{pesel}", Customer.class, "1234567890");
-        Customer cc = template.getForObject("/customers/{id}", Customer.class, c.getId());
+        Customer c = template.getForObject("/customers/pesel/{pesel}", Customer.class, CUSTOMER_PESSEL);
+        Customer cc = template.getForObject("/customers/{id}", Customer.class, id);
         assertNotNull(cc);
         assertTrue(cc.getAccounts().size() > 0);
     }
📄 account-service/src/test/java/pl/piomin/microservices/advanced/account/api/AccountControllerTest.java

Create a new file with the following content:

package pl.piomin.microservices.advanced.account.api;

import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
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.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import pl.piomin.microservices.advanced.account.model.Account;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
    properties = {"spring.cloud.discovery.enabled=false"})
@Testcontainers
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class AccountControllerTest {

    @Container
    static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:8.0");

    @DynamicPropertySource
    static void registerMongoProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.data.mongodb.uri", () -> mongoDBContainer.getConnectionString() + "/test");
    }

    @Autowired
    TestRestTemplate restTemplate;

    private static String accountId;
    private static final String ACCOUNT_NUMBER = "ACC12345678";
    private static final String CUSTOMER_ID    = "CUST12345";

    @Test
    @Order(1)
    public void testAddAccount() {
        Account account = new Account();
        account.setNumber(ACCOUNT_NUMBER);
        account.setCustomerId(CUSTOMER_ID);
        account.setBalance(5000);

        ResponseEntity<Account> response = restTemplate.postForEntity("/accounts", account, Account.class);
        assertEquals(HttpStatus.OK, response.getStatusCode());
        Account created = response.getBody();
        assertNotNull(created);
        assertNotNull(created.getId());
        assertEquals(ACCOUNT_NUMBER, created.getNumber());
        assertEquals(CUSTOMER_ID, created.getCustomerId());
        assertEquals(5000, created.getBalance());
        accountId = created.getId();
    }

    @Test
    @Order(2)
    public void testFindByNumber() {
        ResponseEntity<Account> response = restTemplate.getForEntity("/accounts/{number}", Account.class, ACCOUNT_NUMBER);
        assertEquals(HttpStatus.OK, response.getStatusCode());
        Account found = response.getBody();
        assertNotNull(found);
        assertEquals(accountId, found.getId());
        assertEquals(ACCOUNT_NUMBER, found.getNumber());
        assertEquals(CUSTOMER_ID, found.getCustomerId());
    }

    @Test
    @Order(3)
    public void testFindByCustomer() {
        ResponseEntity<List<Account>> response = restTemplate.exchange(
            "/accounts/customer/{customerId}",
            HttpMethod.GET,
            null,
            new ParameterizedTypeReference<List<Account>>() {},
            CUSTOMER_ID);
        assertEquals(HttpStatus.OK, response.getStatusCode());
        List<Account> list = response.getBody();
        assertNotNull(list);
        assertFalse(list.isEmpty());
        assertEquals(1, list.size());
        assertEquals(accountId, list.get(0).getId());
        assertEquals(ACCOUNT_NUMBER, list.get(0).getNumber());
    }

    @Test
    @Order(4)
    public void testFindAll() {
        ResponseEntity<List<Account>> response = restTemplate.exchange(
            "/accounts",
            HttpMethod.GET,
            null,
            new ParameterizedTypeReference<List<Account>>() {});
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertNotNull(response.getBody());
        assertFalse(response.getBody().isEmpty());
    }

    @Test
    @Order(5)
    public void testUpdateAccount() {
        ResponseEntity<Account> getResp = restTemplate.getForEntity("/accounts/{number}", Account.class, ACCOUNT_NUMBER);
        Account account = getResp.getBody();
        assertNotNull(account);
        int newBalance = 7500;
        account.setBalance(newBalance);
        restTemplate.put("/accounts", account);
        ResponseEntity<Account> updatedResp = restTemplate.getForEntity("/accounts/{number}", Account.class, ACCOUNT_NUMBER);
        assertEquals(newBalance, updatedResp.getBody().getBalance());
        assertEquals(accountId, updatedResp.getBody().getId());
    }
}
📄 product-service/src/test/java/pl/piomin/microservices/advanced/product/api/ProductControllerTest.java

Create a new file with the following content:

package pl.piomin.microservices.advanced.product.api;

import io.specto.hoverfly.junit.core.Hoverfly;
import io.specto.hoverfly.junit.core.config.LogLevel;
import io.specto.hoverfly.junit5.HoverflyExtension;
import io.specto.hoverfly.junit5.api.HoverflyConfig;
import io.specto.hoverfly.junit5.api.HoverflyCore;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
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.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import pl.piomin.microservices.advanced.product.model.Product;
import pl.piomin.microservices.advanced.product.model.ProductType;

import java.time.LocalDate;
import java.util.List;

import static io.specto.hoverfly.junit.core.SimulationSource.dsl;
import static io.specto.hoverfly.junit.dsl.HoverflyDsl.service;
import static io.specto.hoverfly.junit.dsl.ResponseCreators.success;
import static io.specto.hoverfly.junit.dsl.matchers.HoverflyMatchers.startsWith;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
    properties = {"spring.cloud.discovery.enabled=false"})
@Testcontainers
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@HoverflyCore(config = @HoverflyConfig(logLevel = LogLevel.DEBUG))
@ExtendWith(HoverflyExtension.class)
public class ProductControllerTest {

    @Container
    static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:8.0");

    @DynamicPropertySource
    static void registerMongoProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.data.mongodb.uri", () -> mongoDBContainer.getConnectionString() + "/test");
    }

    @Autowired
    TestRestTemplate template;

    private static String productId;
    private static final String ACCOUNT_ID       = "ACC987654";
    private static final String CUSTOMER_ID      = "CUST987654";
    private static final int    INITIAL_BALANCE  = 10000;

    @Test
    @Order(1)
    public void testAddProduct() {
        Product product = new Product();
        product.setAccountId(ACCOUNT_ID);
        product.setCustomerId(CUSTOMER_ID);
        product.setType(ProductType.CREDIT);
        product.setBalance(INITIAL_BALANCE);
        product.setDateOfStart(LocalDate.now());

        ResponseEntity<Product> response = template.postForEntity("/products", product, Product.class);
        assertEquals(HttpStatus.OK, response.getStatusCode());
        Product created = response.getBody();
        assertNotNull(created);
        assertNotNull(created.getId());
        assertEquals(ACCOUNT_ID, created.getAccountId());
        assertEquals(CUSTOMER_ID, created.getCustomerId());
        assertEquals(ProductType.CREDIT, created.getType());
        assertEquals(INITIAL_BALANCE, created.getBalance());
        assertNotNull(created.getDateOfStart());
        productId = created.getId();
    }

    @Test
    @Order(2)
    public void testFindByAccountId() {
        ResponseEntity<Product> response = template.getForEntity("/products/account/{accountId}", Product.class, ACCOUNT_ID);
        assertEquals(HttpStatus.OK, response.getStatusCode());
        Product found = response.getBody();
        assertNotNull(found);
        assertEquals(productId, found.getId());
        assertEquals(ACCOUNT_ID, found.getAccountId());
        assertEquals(CUSTOMER_ID, found.getCustomerId());
        assertEquals(ProductType.CREDIT, found.getType());
    }

    @Test
    @Order(3)
    public void testFindById(Hoverfly hoverfly) {
        hoverfly.simulate(
            dsl(service("http://account-service")
                .get(startsWith("/accounts/" + productId))
                .willReturn(success("{\"id\":\"" + productId + "\",\"customerId\":\"" + CUSTOMER_ID + "\"}", "application/json"))));
        ResponseEntity<Product> response = template.getForEntity("/products/{id}", Product.class, productId);
        assertEquals(HttpStatus.OK, response.getStatusCode());
        Product found = response.getBody();
        assertNotNull(found);
        assertEquals(productId, found.getId());
        assertEquals(ACCOUNT_ID, found.getAccountId());
        assertEquals(CUSTOMER_ID, found.getCustomerId());
    }

    @Test
    @Order(4)
    public void testFindAll() {
        ResponseEntity<List<Product>> response = template.exchange(
            "/products", HttpMethod.GET, null, new ParameterizedTypeReference<List<Product>>() {});
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertNotNull(response.getBody());
        assertFalse(response.getBody().isEmpty());
    }

    @Test
    @Order(5)
    public void testFindByNonExistentAccountId() {
        ResponseEntity<Product> response = template.getForEntity(
            "/products/account/{accountId}", Product.class, "non-existent-account");
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertNull(response.getBody());
    }
}
📄 account-service/src/test/java/pl/piomin/microservices/advanced/account/config/AccountContainersConfiguration.java

Create this TestConfiguration class:

package pl.piomin.microservices.advanced.account.config;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;

@TestConfiguration
public class AccountContainersConfiguration {

    @Container
    private static final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:8.0");

    static {
        mongoDBContainer.start();
    }

    @DynamicPropertySource
    static void setProperties(DynamicPropertyRegistry registry) {
        String uri = mongoDBContainer.getConnectionString() + "/test";
        registry.add("spring.data.mongodb.uri", () -> uri);
    }

    @Bean
    public MongoDBContainer mongoDbContainer() {
        return mongoDBContainer;
    }
}
📄 customer-service/src/test/java/pl/piomin/microservices/advanced/customer/config/CustomerContainersConfiguration.java

Create this TestConfiguration class:

package pl.piomin.microservices.advanced.customer.config;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;

@TestConfiguration
public class CustomerContainersConfiguration {

    @Container
    private static final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:8.0");

    static {
        mongoDBContainer.start();
    }

    @DynamicPropertySource
    static void setProperties(DynamicPropertyRegistry registry) {
        String uri = mongoDBContainer.getConnectionString() + "/test";
        registry.add("spring.data.mongodb.uri", () -> uri);
    }

    @Bean
    public MongoDBContainer mongoDbContainer() {
        return mongoDBContainer;
    }
}
📄 product-service/src/test/java/pl/piomin/microservices/advanced/product/config/ProductContainersConfiguration.java

Create this TestConfiguration class:

package pl.piomin.microservices.advanced.product.config;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;

@TestConfiguration
public class ProductContainersConfiguration {

    @Container
    private static final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:8.0");

    static {
        mongoDBContainer.start();
    }

    @DynamicPropertySource
    static void setProperties(DynamicPropertyRegistry registry) {
        String uri = mongoDBContainer.getConnectionString() + "/test";
        registry.add("spring.data.mongodb.uri", () -> uri);
    }

    @Bean
    public MongoDBContainer mongoDbContainer() {
        return mongoDBContainer;
    }
}
📄 integration-tests/src/test/java/pl/piomin/microservices/advanced/integration/ServiceIntegrationTests.java

Create a new test class annotated with:
- @SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
- @ContextConfiguration(classes = {pl.piomin.microservices.advanced.account.config.AccountContainersConfiguration.class, pl.piomin.microservices.advanced.customer.config.CustomerContainersConfiguration.class, pl.piomin.microservices.advanced.product.config.ProductContainersConfiguration.class})
- @testcontainers
- @TestMethodOrder(MethodOrderer.OrderAnnotation.class)

  Autowire a TestRestTemplate and define tests in the following order:
  1. testAccountCreation: POST /accounts and verify HTTP 200 and returned id.
  2. testCustomerCreation: POST /customers and verify HTTP 200 and returned id.
  3. testProductCreation: POST /products referencing created account and customer, verify HTTP 200.
  4. testServiceToServiceFlow: GET /products/{id} and verify that the product payload includes customer details retrieved from customer-service or account-service.
  5. testFailureScenario: GET /products/{randomId} and assert HTTP status 404 or null body.

  Use assertions from JUnit (assertEquals, assertNotNull, assertFalse) and proper ordering via @Order.

A summary of the context that CodeRabbit is considering across the codebase:

Verify the AccountRepository interface to ensure the query methods we intend to test actually exist.

Locate and inspect the CustomerRepository interface to confirm the return types and method names used in our new tests.

Confirm the path of the CustomerControllerTests file so we can modify it correctly.

Locate the AccountRepository interface to confirm it declares the methods used in our enhanced tests (findByNumber, findByCustomerId, findAll).

Inspect the AccountRepository interface to verify method signatures.

Locate the CustomerRepository interface to confirm it declares findByPesel and inherited findAll.

Inspect the CustomerRepository interface to verify method signatures.

Locate the ProductRepository interface to confirm it declares findByAccountId and inherited findAll.

Inspect the ProductRepository interface to verify method signatures.

Inspect the integration test application to understand how to bootstrap all microservices for writing a comprehensive ServiceIntegrationTests.

  • Executed edits - (🔄 Check again to try again)

Copy link
Contributor

coderabbitai bot commented May 13, 2025

Creating a PR to execute the edits....

The changes have been created in this pull request: View PR

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant