Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Ability to Inject MockBeans in Helidon #7694

Closed
abhinavms opened this issue Oct 2, 2023 · 1 comment
Closed

Ability to Inject MockBeans in Helidon #7694

abhinavms opened this issue Oct 2, 2023 · 1 comment
Assignees
Labels
enhancement New feature or request P3 testing
Projects

Comments

@abhinavms
Copy link

Problem

Helidon currently lacks an equivalent to Spring Boot's @MockBean annotation, which allows for the injection of mock beans into the application context, ensuring that mock dependencies are used when running the application. This feature is essential for improving integration tests in Helidon.

Sample Usecase: Pact (Contract Testing)

One critical use case for this enhancement is contract testing, such as Pact testing, where microservices need to be tested in isolation to ensure their interactions conform to predefined contracts.

Suppose there are two microservices, X and Y, where X calls Y. Consumer tests are created by microservice X, specifying the endpoint, request, and expected response. For such tests to be effective, we need the ability to inject mock dependencies into the running server.

Sample consumer test

{
  "consumer": {
    "name": "X"
  },
  "interactions": [
    {
      "description": "Check if the product exists",
      "providerStates": [
        {
          "name": "Product X010000021 exists"
        }
      ],
      "request": {
        "body": {
          "instance": "v2211",
          "pushToURL": "https://XXXXXX.com"
        },
        "headers": {
          "Content-Type": "application/json"
        },
        "method": "POST",
        "path": "/v1/product/check"
      },
      "response": {
        "status": 200
      }
    }
  ],
  "provider": {
    "name": "Y"
  }
}

This consumer test is run at the microservice Y, to valid if the request returns the expected response (In the above example POST to /v1/product/check with the provided request should return a status 200)

Spring Boot Example

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Provider("Y")
public class PricingServiceProviderPactTest {

  @MockBean
  private ProductClient productClient;  // Replaces the bean with a mock in the application context

  @LocalServerPort
  private int port;

  @BeforeEach
  void before(PactVerificationContext context) {
    context.setTarget(new HttpTestTarget("localhost", port, "/"));
  }

  @TestTemplate
  @ExtendWith(PactVerificationInvocationContextProvider.class)
  void pactVerificationTestTemplate(PactVerificationContext context, HttpRequest request) {
    context.verifyInteraction();
  }

  @State("Product X010000021 exists")
  public void setupProductX010000021() {
    when(productClient.fetch((Set<String>) argThat(contains("X010000021")), any())).thenReturn(product);
  }
}

In Spring Boot, the server starts, and the ProductClient is injected with a mock. When Pact runs the consumer tests, it calls the REST endpoint of the server, and since we can mock the injections, we can return the required data without actually performing the operation.

Helidon Example

In contrast, in Helidon, for a running server, you cannot inject a MockBean. Therefore, the only way to test the Pact is to create a new server with a mocked endpoint class. However, this approach does not constitute real integration testing, as the actual REST endpoint is not called. Consequently, if any changes occur in the server's path, the consumer test may not break, as the endpoint is manually specified in the test router.

SampleProviderTest

@HelidonTest
@Provider("Y")
@DisableDiscovery
@AddExtensions({
        @AddExtension(ServerCdiExtension.class),
        @AddExtension(JaxRsCdiExtension.class),
        @AddExtension(CdiComponentProvider.class)
})
public class SampleProviderTest implements SampleEndpointMocked {
    @Inject
    WebTarget webTarget;

    @Mock
    ProductClient productClient;

    @BeforeEach
    void before(PactVerificationContext context) {
        String host = webTarget.getUri().getHost();
        int port = webTarget.getUri().getPort();
        context.setTarget(new HttpTestTarget(host, port, "/"));
    }

    @TestTemplate
    @ExtendWith(PactVerificationInvocationContextProvider.class)
    void pactVerificationTestTemplate(PactVerificationContext context, HttpRequest request) {
        context.verifyInteraction();
    }

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @State("Product X010000021 exists")
    public void setupProductX010000021() {
        when(productClient.fetch((Set<String>) argThat(contains("X010000021")), any())).thenReturn(product);
    }

    @Override
    public ProductClient productClient() {
        return productClient;
    }
}

SampleEndpointMocked

@Path("/v1/product/check")
@ApplicationScoped
public interface SampleEndpointMocked {

    ProductClient productClient();
    
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    default Response sampleEndPoint(@HeaderParam("Authorization") String authHeaderValue, String inputJson) {
        ApplicationEndpoint applicationEndpoint = new ApplicationEndpoint(productClient());
        return applicationEndpoint.actualEndpoint(authHeaderValue, inputJson);
    }
}
@github-actions github-actions bot added this to Triage in Backlog Oct 2, 2023
@m0mus m0mus added enhancement New feature or request testing P3 labels Oct 5, 2023
@m0mus m0mus moved this from Triage to Normal priority in Backlog Oct 5, 2023
@jbescos jbescos self-assigned this Apr 17, 2024
jbescos added a commit to jbescos/helidon that referenced this issue Apr 18, 2024
Signed-off-by: Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com>
jbescos added a commit to jbescos/helidon that referenced this issue Apr 18, 2024
Signed-off-by: Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com>
jbescos added a commit to jbescos/helidon that referenced this issue Apr 18, 2024
Signed-off-by: Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com>
romain-grecourt pushed a commit that referenced this issue May 17, 2024
* 4.x: Ability to Inject MockBeans in Helidon #7694

Signed-off-by: Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com>
@jbescos
Copy link
Member

jbescos commented May 20, 2024

Merged

@jbescos jbescos closed this as completed May 20, 2024
Backlog automation moved this from Normal priority to Closed May 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request P3 testing
Projects
Backlog
  
Closed
Development

No branches or pull requests

3 participants