[JAVA] 05. I tried to stub the source of Spring Boot

Overview

This is the fifth in the Spring Boot series. This time, I will explain ** how to stub the source ** with a little change from the past.

I think that the most common ones are ** Mockito in UT and mocking by wiremock in FT **. If you bootRun, each mock will not work, so you may have trouble with HTTP communication failure or not being able to connect to the DB.

If you make it a stub by the method I will introduce from now on, ** It is possible to use stubs in some environments and hit the actual API only in the environment where the opposite API exists **.

I hope it will be helpful for those in need! !!

Main subject

What kind of method is used to stub the source? ** Register the stub class with the same name as the class you want to stub in the DI container, add @Primary and replace it **, I will do that.

1. Try to implement using RestTemplate as appropriate

It appears several times in my article, but I use the ** Zip Code Search API **. As the name suggests, it is an API that returns address information in the response body when you request by putting the zip code on the query parameter.

For the implementation, see here. Let's bootRun and hit what kind of result will be returned.

First, try requesting an existing address. 無題1.png You have successfully obtained the zip code and prefecture code. The normal system looks like this.

So what if you request an address that doesn't exist? 無題2.png

Of course, if you type a zip code that doesn't exist, you'll get an empty response **.

… So what if you had to release this app in an environment where the ** zip code search API doesn't exist? ** ** Needless to say, no matter what zip code you request, you'll get a 404 error ** and it's useless.

Let's make a stub and deal with it ** for such a case! !!

2. Implement the stub class

I think it's easier to imagine while looking at the implementation class. First, put the implementation class.

MockClient.java


@Configuration // (1)
public class MockClient {
    @Bean // (1)
    @Primary // (1)
    public GetAddressApiClient mockGetAddressApiClient(RestTemplateBuilder restTemplateBuilder,
                                                       ResponseHandlerInterceptor interceptor) {
        return new MockGetAddressApiClient(restTemplateBuilder, interceptor);
    }

    static class MockGetAddressApiClient extends GetAddressApiClient { // (2)
        MockGetAddressApiClient(RestTemplateBuilder restTemplateBuilder,
                                ResponseHandlerInterceptor interceptor) {
            super(restTemplateBuilder, interceptor);
        }

        @Override
        public GetAddressApiResponse request(String zipCode) {
            return new GetAddressApiResponse( // (3)
                    "200",
                    "",
                    Arrays.asList(
                            new GetAddressApiResponse.Result(
                                    "zipcode",
                                    "prefcode",
                                    "address1",
                                    "address2",
                                    "address3",
                                    "kana1",
                                    "kana2",
                                    "kana3"
                            ),
                            new GetAddressApiResponse.Result(
                                    "zipcode",
                                    "prefcode",
                                    "address1",
                                    "address2",
                                    "address3",
                                    "kana1",
                                    "kana2",
                                    "kana3"
                            )
                    )
            );
        }
    }
}

I will explain each point!

(1). Register in the DI container with @ Configuration +@ Primary (@Bean)

Bean definition by annotation is possible in Spring, and stub class is registered in DI container with @ Configuration + @ Bean used at that time. However, at this time, since the real GetAddressApiClient is also registered, ** there will be two beans with the same name, and Spring will raise an exception. ** ** Use ** @ Primary ** to get around it! As a result, the one with @Primary will be given priority. In other words, ** the stub class will always be used **.

(2). Create a stub class that inherits the class to be stubized.

Next, create the stub class itself. As mentioned above, this time it is necessary to register the bean with the same type as the real class. To do this, ** create a stub class by inheriting the real class **. It's relatively important.

(3). @Override the method and define the return value

The rest is the definition of the return value. In this case, override the request method and return any return value you like.

Try hitting

Let's bootRun and hit. 無題.png Since the response written in the stub is returned, It seems that it has been successfully made into a stub!

… But here is another question. ** "This stub always works, so maybe the real class doesn't work?" ** …That's right. This time, on the contrary, it has become an application that only works with stubs.

So ** Let's make it possible to use the real thing and the stub properly for each environment! !! ** **

3. Specify the environment to which the stub is applied

** Add @Profile to the stub class **. As a result, ** the stub class will be DI-registered only in the specified environment, and the stub class will not be DI-registered in the unspecified environment (≒ real works) **.

MockClient.java


@Configuration
@Profile("dev")
public class MockClient {
    //abridgement
}

In the above case, it will be a stub class only in the dev environment, and the real Client class will work in other environments!

Finally

Thank you for watching until the end! When I looked it up, I found that there weren't many articles like this, so I hope it helps someone!

We welcome your comments and comments!

Recommended Posts

05. I tried to stub the source of Spring Boot
I tried to reduce the capacity of Spring Boot
I want to control the default error message of Spring Boot
The story of raising Spring Boot 1.5 series to 2.1 series
[Spring Boot] I investigated how to implement post-processing of the received request.
I tried to summarize the state transition of docker
I tried to clone a web application full of bugs with Spring Boot
I read the source of ArrayList I read
I read the source of Integer
I tried to explain the method
I read the source of Long
I tried GraphQL with Spring Boot
I read the source of Short
I tried Flyway with Spring Boot
I read the source of Byte
I read the source of String
About the function of Spring Boot due to different versions
I tried to summarize the basics of kotlin and java
I tried to verify this and that of Spring @ Transactional
[Swift] I tried to implement the function of the vending machine
I tried to summarize the basic grammar of Ruby briefly
I tried to build the environment of WSL2 + Docker + VSCode
I tried to get started with Swagger using Spring Boot
I tried to summarize the methods used
I want to understand the flow of Spring processing request parameters
I tried to build the environment of PlantUML Server with Docker
I tried Spring.
What I did in the migration from Spring Boot 1.4 series to 2.0 series
I tried to implement the Iterator pattern
I tried Lazy Initialization with Spring Boot 2.2.0
I tried to check the operation of gRPC server with grpcurl
What I did in the migration from Spring Boot 1.5 series to 2.0 series
I tried to summarize the Stream API
I tried to summarize the methods of Java String and StringBuilder
I tried to build Ruby 3.0.0 from source
I tried to solve the problem of Google Tech Dev Guide
I want to know the Method of the Controller where the Exception was thrown in the ExceptionHandler of Spring Boot
Procedure to make the value of the property file visible in Spring Boot
I tried to summarize the key points of gRPC design and development
I used Docker to solidify the template to be developed with spring boot.
I tried to make full use of the CPU core in Ruby
I tried to visualize the access of Lambda → Athena with AWS X-Ray
I introduced OpenAPI (Swagger) to Spring Boot (gradle) and tried various settings
I tried to measure and compare the speed of GraalVM with JMH
I want to output the day of the week
Summary of what I learned about Spring Boot
[Rails] I tried to raise the Rails version from 5.0 to 5.2
I tried to organize the session in Rails
I tried to chew C # (basic of encapsulation)
I want to var_dump the contents of the intent
Let's check the feel of Spring Boot + Swagger 2.0
I tried to link JavaFX and Spring Framework.
I tried to set tomcat to run the Servlet.
I wanted to gradle spring boot with multi-project
[Spring Boot] How to refer to the property file
I tried using the profiler of IntelliJ IDEA
[I tried] Spring tutorial
I tried Spring Batch
03. I sent a request from Spring Boot to the zip code search API
I tried to compare the infrastructure technology of engineers these days with cooking.
How to set environment variables in the properties file of Spring boot application