SonarQube demanding tests on conditions for Spring application with mock components

I have a Spring Boot service implementation that communicates with three different external services (APIs and SOAP Web Services). Some times those services can go into maintenance and I needed to implement a mechanism to “bypass” or “mock” them. The approach I am following to achieve this is to include some entries in the properties file:

service1.bypass.enable=true
service2.bypass.enable=true
service3.bypass.enable=true

So inside my code I just need to verify if those properties have value set in true and either use the right implementation or bypass (return a mock).

@Value("service1.bypass.enable")
private boolean service1Bypass;
//Inside the methods
if (!service1Bypass) {
   callService();
} else {
   callMock();
}

This is causing some troubles at the moment my code is scanned by SonarQube because I need to test when each service is mocked or not which I think is not relevant. Do you know if there’s any workaround or a better way to code this? this project is using Spring and Maven with Java 8

1 answer

  • answered 2018-08-14 21:34 Marcelo Tataje

    I believe there’s a misconception between “bypassing” and “mocking”.

    When you bypass a service, it means you “skip” it, in other words you do not call that service and move forward with your next steps.

    When you "mock" a service, your logic is not “skipping” the call to that service, you create a component (that belongs to your code project) that would imitate the behavior of the real service but it will return some “test” or “fake” response.

    Mocking is pretty useful technique for testing or for the scenario you describe in which many of the services you are consuming can go into maintenance and impact other people that want to consume your service.

    Now, going back to the problem you have, you can solve this in two ways, the first one, if you are using the Jacoco Coverage Plugin, then just add the following tags to your pom.xml file (since I believe you are using maven).

    <properties>
        <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
        <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
        <sonar.jacoco.reportPaths>target/jacoco.exec</sonar.jacoco.reportPaths>
        <sonar.language>java</sonar.language>
        <sonar.exclusions>YOUR PACKAGES GOES HERE</sonar.exclusions>
    </properties>
    

    Besides that, I believe your approach is not bad, but it can lead to some issues such:

    • You are mixing your “mocking” logic inside the business logic which can be a little bit messy.
    • When analyzing the code with tools such SonarQube (static analysis), you will find that each condition usually demands a test case (which I believe is the problem you have)
    • You are using now three properties because you connect to three services, but what if you need to consume eight or nine services? Would you add eight or nine properties? I mean, you can, but can be a little messy IMHO.

    Since you are already using Spring, I believe that more than a workaround, a good approach to solve the issues would be to take a look to Spring Profiles.

    For a more detailed tutorial you can also take a look to: https://www.baeldung.com/spring-profiles

    Let’s take an example for your case:

    1. You will only need to define one property instead one for each service in your properties file, this property is called: spring.profiles.active
    2. You can assign one or more values to that property (separated by commas).

    For instance: If you want to mock one of the services, you can go with the following: spring.profiles.active=mockservice1

    If you want to mock two (or more) services: spring.profiles.active=mockservice1,mockservice2

    1. Instead of using conditional structures, you will create a class for each service you want to mock and annotate with @Profile(“mockservice1”) or handle through @Configuration or @Bean annotations.

    Hope this can help you in some way to fix your issues.