Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock an Eureka Feign Client for Unittesting

i am using spring cloud's eureka and feign to communicate between some services (lets say A and B). Now id like to unittest my service layer of a single service (A). The problem is, that this service (A) is using a feign client to request some information of the other service (B).

Running the unittests without any special configuration throws the following exception: java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: service-b => but i do not want any server to run.

My question is: Is there a way to mock the feign client, so i can unittest my service (A) without running an eureka instance and service (B)?

Edit: I ended up creating a stub for the feign client. The stub is marked as a primary component to force spring instantiating the stub within my tests.
This is the solution i came up with.

//the feign client
@FeignClient("user") 
public interface UserClient { 
    UserEntity getUser(); 
}

//the implementation i use for the tests 
@Component 
@Primary //mark as primary implementation
public class UserClientTestImpl implements UserClient { 
    @Override public UserEntity getUser() { 
        return someKindOfUser; 
    } 
}
like image 511
Kamil Szuster Avatar asked Dec 21 '15 14:12

Kamil Szuster


People also ask

How do you mock feign client response?

Mocking a feign client is really useful in microservice component tests. You want to test one microservice without having to start all the other microservices. If you're using Spring (and it looks like you are), the @MockBean annotation together with a bit of Mockito code will do the job.

Can we use feign client without Eureka?

Yes you can use Feign without Ribbon, All you need to do is specify the base url in your Feign Java interface class.

How would you implement feign client in microservices?

Let's implement the Feign in our project and invoke other microservices using Feign. Step 1: Select currency-conversion-service project. Step 2: Open the pom. xml and add the Feign dependency.


3 Answers

The question is ... do you even need to mock? I often see that people mention "mock" as the first solution to anything that "should not be part of the unit test". Mocking is a technique, not the solution to everything. (see here).

If you are still at the early stages of your code, just refactor and use something else instead of depending on the concrete instance of the Feign Client. You might use an interface, an abstract class, a trait or whatever you want. Don't depend on the object itself, otherwise you have to "mock it".

public interface IWebClient {
  public String get(...);
  public String post(...);
} 

To the question: but I will have other code that will do exactly the same (except that it will be on the concrete instance of Feign), what do I do then? Well, you can write a functional test and call an instance of a web server that you can setup locally - or use Wiremock, as mentioned by Marcin Grzejszczak in one of the answers.

public class FeignClientWrapper implements IWebClient {
  private feign = something

  public String get() {
    feign.get( ... ) 
  }

  public String post() {
    feign.post( ... ) 
  }
} 

Unit tests are used to test algorithms, if/else, loops: how units work. Don't write code to make mocks fit - it must be the other way around: your code should have less dependencies, and you should mock only when you need to verify the behavior (otherwise you can use a stub or a fake object): do you need to verify the behavior? Do you need to test that a particular method gets called in your code? Or that a particular method gets called with X, Y, and Z for 3 times in a row? Well, then yes, mocking is ok.

Otherwise, use a fake object: what you want is to test just the call/response and maybe the status code. All you probably want is to test how your code reacts to different outputs (e.g., the field "error" is present or not in a JSON response), different status codes (assuming that the Client documentation is right: 200 OK when GET, 201 when POST, etc).

like image 67
Markon Avatar answered Oct 12 '22 15:10

Markon


Mocking a feign client is really useful in microservice component tests. You want to test one microservice without having to start all the other microservices.

If you're using Spring (and it looks like you are), the @MockBean annotation together with a bit of Mockito code will do the job.

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = 
SpringBootTest.WebEnvironment.DEFINED_PORT)
public class TestYourComponent {
    @Configuration
    @Import({YourConfiguration.class})
    public static class TestConfiguration {
    }

    @MockBean
    private UserClient userClient;

    @Test
    public void someTest()
    {
        //...
        mockSomeBehavior();
        //...
    }

    private void mockSomeBehavior() {
        Mockito.doReturn(someKindOfUser).when(userClient).getUser();
    }
}
like image 21
Myrle Krantz Avatar answered Oct 12 '22 17:10

Myrle Krantz


If you need to use a mock you can use Wiremock to stub the response for a given request - http://wiremock.org/stubbing.html. That way you will do integration tests with real HTTP requests sent. For unit testing the answer from @Markon is very good.

like image 4
Marcin Grzejszczak Avatar answered Oct 12 '22 17:10

Marcin Grzejszczak