E2E Testing Pipeline for Spring Boot Microservices using OpenFeign Client and Github Actions
In this article, I will show you how to quickly setup E2E Testing Pipeline for your Spring Boot Microservices Project using OpenFeign Client and Github Actions.
You can find the full source code here:
@RestController
@RequestMapping("/test-data")
public class TestDataController {
private static final Logger LOGGER = LoggerFactory.getLogger(DepartmentController.class);
DepartmentRepository repository;
public TestDataController(DepartmentRepository repository) {
this.repository = repository;
}
@DeleteMapping("/delete/department")
public ResponseEntity<Void> deleteAllDepartments() {
repository.deleteAll();
return ResponseEntity.noContent().build();
}
@DeleteMapping("/delete/department/{id}")
public ResponseEntity<Void> deleteDepartment(@PathVariable("id") String id) {
repository.deleteById(id);
return ResponseEntity.noContent().build();
}
}
2. application-test.yml - In this configuration file, you provide actual base URLs to all your REST API Clients. These URLs are used by Feign Client. You also need to disable SSL validation, if you are using SSL in your testing environment.
spring.cloud.openfeign.client.config.department.url=https://erp.greeta.net/department
spring.cloud.openfeign.client.config.testData.url=https://erp.greeta.net/department/test-data
feign.httpclient.disableSslValidation=true
3. FeignClientConfiguration - This Feign Client Configuration disables SSL validation for your clients. You need this configuration for testing purposes, if you are using SSL in your testing environment.
@Configuration
public class FeignClientConfiguration {
@Bean
public Client feignClient()
{
Client trustSSLSockets = new Client.Default(getSSLSocketFactory(), new NoopHostnameVerifier());
return trustSSLSockets;
}
private SSLSocketFactory getSSLSocketFactory() {
try {
TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
};
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
return sslContext.getSocketFactory();
} catch (Exception exception) {
}
return null;
}
}
4.TestDataClient - This is the client for your Test Data REST API Controller, which you created in Step 1. OpenFeign is similar to Spring Data JPA, but for REST API. As you see, in this and the next example, you provide annotated interface with strong typed method parameters and OpenFeign automatically implements this Interface. You can then use such clients in the main code and in the tests and it will feel as if you are working with simple Java objects, not actual HTTP Client behind the scene.
@FeignClient(name = "testData")
public interface TestDataClient {
@DeleteMapping("/delete/department")
public void deleteAllDepartments();
}
Recommended by LinkedIn
5. DepartmentTestClient - This is the client for Department REST API Controller (You can easily find DepartmentController in the Github Source code). OpenFeign is similar to Spring Data JPA, but for REST API. You provide annotated interface with strong typed method parameters and OpenFeign automatically implements this Interface.
@FeignClient(name = "department")
public interface DepartmentTestClient {
@GetMapping("/{id}")
public Department findById(@PathVariable("id") String id);
@PostMapping("/")
public Department add(@RequestBody Department department);
@GetMapping("/")
public Iterable<Department> findAll();
@GetMapping("/organization/{organizationId}")
public List<Department> findByOrganization(@PathVariable("organizationId") String organizationId);
}
6. DepartmentE2ETest - This is the actual E2E Test, which uses OpenFeign Clients for REST API Calls. In these tests you can use any Java classes from your main code. Any domain objects, which you use in the main code or in other tests can be reused in your E2E tests. In contrast to RestAssured, you have real strong typing here: no need to learn complex logic for resolving JSON structure. In contrast to SwaggerCodeGen, you don't need to generate any Source Code and regenerate it after any changes in REST API Controllers. OpenFeign Clients are completely decoupled from REST API Controllers in your main code. You can change them independently. Also, if anything changes in REST API Controllers and your OpenFeign Clients are not changed, then your E2E tests will fail, which makes your tests very practical regression tests, which are in sync with your REST API.
@SpringBootTest
@TestPropertySource(locations = {
"classpath:application.yml",
"classpath:application-test.yml"
})
public class DepartmentE2eTest {
@Autowired
private DepartmentTestClient departmentClient;
@Autowired
private TestDataClient testDataClient;
@BeforeEach
void cleanup() {
testDataClient.deleteAllDepartments();
}
@Test
void addDepartmentTest() {
Department department = new Department("1", "Test");
department = departmentClient.add(department);
assertNotNull(department);
assertNotNull(department.getId());
}
@Test
void addAndThenFindDepartmentByIdTest() {
Department department = new Department("2", "Test2");
department = departmentClient.add(department);
assertNotNull(department);
assertNotNull(department.getId());
department = departmentClient.findById(department.getId());
assertNotNull(department);
assertNotNull(department.getId());
}
@Test
void findAllDepartmentsTest() {
Department[] departments = StreamSupport.stream(departmentClient.findAll().spliterator(), false).toArray(Department[]::new);
assertEquals(0, departments.length);
}
@Test
void findDepartmentsByOrganizationTest() {
Department department = new Department("1", "Test");
department = departmentClient.add(department);
assertNotNull(department);
assertNotNull(department.getId());
List<Department> departments = departmentClient.findByOrganization("1");
assertEquals(1, departments.size());
}
}
7. pom.xml - This change is required, in order to prevent other tests from running E2E tests. E2E tests should be run in separate pipeline, when DEV or Staging Environments are ready. It is not recommended to run such tests in your standard testing pipeline, because they depend on your DEV or Staging environment and usually take longer time to run, than other tests.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/*E2eTest.java</exclude>
</excludes>
<failIfNoSpecifiedTests>false</failIfNoSpecifiedTests>
</configuration>
</plugin>
8.acceptance-stage.yml - This is example of Github Actions workflow file, which triggers E2E Testing Pipeline. The best way is to integrate this workflow with your deployment to DEV or Staging. In this simple example, you can run this workflow manually, after you deploy your Envrionment to AWS with Terraform (or use your own preferred way of infrastructure deployment). See this post for more details on Deployment to AWS with Terraform: https://www.garudax.id/feed/update/urn:li:activity:7096286674795520000/
name: Acceptance Stage
on:
workflow_dispatch:
jobs:
e2e:
name: E2E Tests
runs-on: ubuntu-22.04
permissions:
contents: read
packages: write
security-events: write
steps:
- name: Checkout source code
uses: actions/checkout@v3
- name: Set up JDK
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 17
cache: maven
- name: Run E2E Tests
run: |
mvn test -Dtest="*E2eTest"
Congratulations! You were able to quickly set up E2E Testing pipeline in your environment. Now you are ready to make more tests and add more test coverage to your REST API.
It is recommended to add new E2E Test after every Exploratory Manual Testing Session. If you follow this practice, you will have strong testing coverage with great executable documentation in the form of E2E tests. As a next step, I would recommend to use Gherkin Testing Scenarios and translate them to E2E tests. This will make your E2E tests real executable documentation, completely in sync with your main code. Confluence or Wiki Documentation is great! But it quickly becomes outdated. With your E2E tests it will never happen. Your documentation is always with you, ready to prove that its up-to-date any time.
How can I write FeignClient method for the Spring controller returning ResponseEntity<StreamingResponseBody> This endpoint is being used to generate Excel File
Do we need to set up maven also in the workflow, as I am getting errors in the pipeline? mvn: command not found
Software Engineer | MSCS @ SCU | PKU alumni
2yHi, I am confused about your E2E test. I thought the E2E test would have multiple services communicate with each other. That said, the Department E2E test should communicate with other services such as Organization, Employee, etc. So, how do you spin up other services while running an E2E test? I think that's more important. I don't see you do something similar to this in your E2E test, did I miss something?