Start MockServer during spring-boot:run
Asked Answered
R

3

6

We have some APIs we use in our application that are not accessible from local developer machines due to firewalls.

I want to use mockServer to mock some of these API so we can develop locally.

When running tests mockServer can be started and stopped using the maven build phases process-test-classes and verify respectively.

How can I get it to run when I start the application with mvn spring-boot:run ?

Randa answered 11/6, 2021 at 19:21 Comment(0)
B
0

It's possible to override beans on springboot. So you can use your beans and switch for mock values as you need The example bellow is overriding services and using mock as you prefer but you can use interfaces as well.

Creating a service

@Service
public class ServiceReal {

    @Autowired(required = false) // must be required=false. May be disabled by using mock configuration
    private JdbcTemplate jdbcTemplate;

    public String getInfo() {
        return  jdbcTemplate...// get a real value from database
    }

}

Creating a mock service


@Service
@Primary
@Profile("mocklocal")
public class ServiceMock extend ServiceReal {

    @Override
    public String getInfo() {
        return  "Mocked value"
    }
}

Config beans to choose one of them on properties later

@Profile("mocklocal")
@PropertySource("classpath:application-mocklocal.properties")
@Configuration
public class ConfigMock {

    private static final String  PROP_VALUE_TRUE = "true";
    private static final boolean PROP_FALSE_DEFAULT_MISSING = false;
    private static final String  PROP_SERVICE_REAL = "mocklocal.service.real";
    private static final String  PROP_SERVICE2_REAL = "mocklocal.service2.real";
    
    @Bean
    @ConditionalOnProperty( value = PROP_SERVICE_REAL, havingValue = PROP_VALUE_TRUE, matchIfMissing = PROP_FALSE_DEFAULT_MISSING)
    public ServiceReal serviceReal(){
        return new ServiceMock();
    }
    
    @Bean
    @ConditionalOnProperty( value = PROP_SERVICE2_REAL, havingValue = PROP_VALUE_TRUE, matchIfMissing = PROP_FALSE_DEFAULT_MISSING)
    public Service2Real service2Real(){
        return new Service2Mock();
    }   
}

Config your application-mocklocal.properties to use mock

# using ConfigMock
spring.profiles.active=mocklocal

# settig spring to override service and use mock
spring.main.allow-bean-definition-overriding=true

# disable some configuration not required in mocks. you can adjust for amqp, database or other configuration
spring.autoconfigure.exclude[0]=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
spring.autoconfigure.exclude[1]=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
spring.autoconfigure.exclude[2]=org.springframework.boot.autoconfigure.orm.jpa.DataSourceTransactionManagerAutoConfiguration

# enable your service to use mocks not real services
mocklocal.service.real=true
mocklocal.service2.real=true

so if you start your app using --spring.profiles.active=mocklocal you will got mock values

And you can use on tests as well

@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc
@SpringBootTest
@TestPropertySource(locations = "classpath:application-mocklocal.properties")
public class RunIntegrationTests {

    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void run() throws Exception{
        ...
    }
}
Bootleg answered 13/6, 2021 at 15:58 Comment(0)
H
0

When running tests mockServer can be started and stopped using the maven build phases process-test-classes and verify respectively.

So there must be some (pom) configuration like:

<plugin>
  <groupId>org.mock-server</groupId>
  <artifactId>mockserver-maven-plugin</artifactId>
  <version>3.10.8</version>
  <configuration>
    <serverPort>1080</serverPort>
    <proxyPort>1090</proxyPort>
    <logLevel>DEBUG</logLevel>
    <initializationClass>org.mockserver.maven.ExampleInitializationClass</initializationClass>
  </configuration>
  <executions>
      <execution>
        <id>process-test-classes</id>
        <phase>process-test-classes</phase>
        <goals>
            <goal>start</goal>
        </goals>
      </execution>
      <execution>
        <id>verify</id>
        <phase>verify</phase>
        <goals>
            <goal>stop</goal>
        </goals>
      </execution>
  </executions>
</plugin>

This would start a mock server at process-test-classes (so before test phase) and stop it at validate (so after (post-)integration-test phase). (link1, link2)

How can I get it to run when I start the application with mvn spring-boot:run ?

To run it with mvn spring-boot:run:

  1. Just run mvn mockserver:start spring-boot:run! (pack it into a script/IDE launch..) (recommended)
  2. Implement custom plugin, which commbines spring-boot-maven and mockserver-maven-plugin... (and then run mvn com.example:custom-plugin:run)

.

Harbour answered 24/6, 2021 at 20:57 Comment(0)
B
-1

I had created a MockServer for my team once, for quite a similar purpose here (fortunately a short demo is also available). You can set up this server independently (say on a localhost) and add the request (url and payloads) with the corresponding response json you want to this server.

The one time change you need to do inside your project will be to route all your API request to this Mockserver during development/testing, which can be done by changing the base url of all the APIs you will be using and setting up the mockserver with appropriate json request and response. It can be done as simple as this:

public class BaseUrlLoader {

    public static String NEWSRIVER_BASE_URL;
    public static String FACEBOOK_BASE_URL;
    public static String TWITTER_BASE_URL;

    private static final String MOCKSERVER_BASE_URL = "mocksrvr.herokuapp.com/TEAM-SECRET-KEY";

    public static void load(){
        Properties properties= new Properties();
        String activeProfile;
        try{
            properties.load(ClassLoader.getSystemResourceAsStream("application.properties"));
        } catch (IOException e) {
            System.out.println("Not able to load the application.properties file");
            return;
        }
        activeProfile = properties.getProperty("spring.profiles.active");
        System.out.println("Using "+activeProfile);
        if(activeProfile.equals("Test")){
            NEWSRIVER_BASE_URL=MOCKSERVER_BASE_URL;
            FACEBOOK_BASE_URL= MOCKSERVER_BASE_URL;
            TWITTER_BASE_URL= MOCKSERVER_BASE_URL;
        }else{
            NEWSRIVER_BASE_URL="api.newsriver.io";
            FACEBOOK_BASE_URL="api.facebook.com";
            TWITTER_BASE_URL="api.twitter.com";
        }
        System.out.println(NEWSRIVER_BASE_URL);
    }

}


// Example- Use APIs as
public class NewsFetch {
    
    ...
    
    public NewsFetch(){ BaseUrlLoader.load(); }
    
    private URI buildURL(APIQuery apiQuery) throws URISyntaxException {
        String mainURL = BaseUrlLoader.NEWSRIVER_BASE_URL+"v2/search";
        URIBuilder url = new URIBuilder(mainURL);
        url.addParameter("query", apiQuery.getLuceneQuery());
        url.addParameter("soryBy", apiQuery.getSortBy());
        url.addParameter("sortOrder", apiQuery.getSortOrder());
        url.addParameter("limit", apiQuery.getLimit());
        return url.build();
    }

    public HttpResponse <String> fetch(APIQuery apiQuery) throws URISyntaxException, IOException, InterruptedException {
        URI uri = buildURL(apiQuery);
        HttpRequest request = HttpRequest.newBuilder()
                .GET()
                .header("Authorization", KEY)
                .uri(uri)
                .build();
        ...

    }
}
// and add the request like http://mocksrvr.herokuapp.com/TEAM-SECRET-KEY/v2/search/... to the Mockserver with the response you want.

The baseurl will change according to the current active profile. This mockserver is simple and can even be integrated with the Slackbot. See more in the readme file. There can be many bugs in the project and contributions will be appreciated.

Brookins answered 24/6, 2021 at 14:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.