Mockito test java 8 lambda Consumer API - java

I need to test a class that is using another interface as a dependency injection with a lambda Consumer.
#Builder
public class Interactor {
private final Gateway gateway;
void process(String message, Consumer<String> response){
gateway.process(message, uuid -> {
response.accept(uuid.toString());
});
}
}
The dependency is defined like so:
public interface Gateway {
void process(String message, Consumer<UUID> uuid);
}
How would I mock the Gateway so I can provide a UUID value response to my test?
This is what I have tried so far:
#Test
void whillReturnTheInjectedUUIDValueTest() {
UUID uuid = UUID.randomUUID();
Gateway gateway = Mockito.mock(Gateway.class);
Mockito.when(gateway.process("ignored", uuid1 -> {return uuid;}));
Interactor.builder().gateway(gateway).build().process("ignored", s -> {
Assertions.assertEquals(uuid.toString(), s);
});
}
How should I provide the return value to the consumer?

this one did the trick
#Test
void willReturnTheInjectedUUIDValueTest() {
UUID uuid = UUID.randomUUID();
Gateway gateway = Mockito.mock(Gateway.class);
doAnswer(ans -> {
Consumer<UUID> callback = (Consumer<UUID>) ans.getArgument(1);
callback.accept(uuid);
return null;
}).when(gateway).process(Mockito.any(String.class), Mockito.any(Consumer.class));
Interactor.builder().gateway(gateway).build().process("ignored", s -> {
Assertions.assertEquals(uuid.toString(), s);
});
}
This answer was the hint -> https://stackoverflow.com/a/47226374/148397

For now I ended up mocking my own inner class without Mockito.
class InteractorTest {
#Test
void whillReturnTheInjectedUUIDValueTest() {
UUID uuid = UUID.randomUUID();
Gateway gateway = GatewayMock.builder().value(uuid).build();
Interactor.builder().gateway(gateway).build().process("ignored", s -> {
Assertions.assertEquals(uuid.toString(), s);
});
}
#Builder
private static class GatewayMock implements Gateway {
private final UUID value;
#Override
public void process(String message, Consumer<UUID> uuid) {
uuid.accept(value);
}
}
}

What you want...
is to verify the result of the logic of Interactor#process, which takes a Consumer<String> and basically just calls Gateway#process with a Consumer<UUID> implementation that calls back to the Consumer<String> parameter.
Ideally you want to do this just by calling Interactor#process and verifying the call to the Consumer<String> you supply.
Your problem is...
that it is up to the implementator of Gateway to trigger the Consumer<UUID> (and consequently the Consumer<String>). So you need to inject an implementation of Gateway that does just that.
The solution is...
along the lines of the answer you provided (i.e. using a Fake Object instead of a Mock), unless there is a real implementation of Gateway in your production code that you can easily use instead (but I assume you'd be doing that already if that was the case).
Can you do it with Mockito? Sure, you can call methods on a mock object's method arguments, as shown in this answer: https://stackoverflow.com/a/16819818/775138 - but why would you go there if you can provide a sufficient Gateway implementation in a single line:
Gateway gw = (message, consumer) -> consumer.accept(uuid);
where uuid is the UUID instance that you constructed before. So no need to declare a static inner class just for this.
However...
there is an important issue with your assertion: if Interactor does nothing at all instead of calling the Gateway, the Consumer<String> you provide (containing the assertion) won't get triggered, so your test will pass! Just assign the value to a member variable of your test class, and assert on that outside the lambda.

Related

How to iterate element in a method after converting to List?

I have the following endpoint:
public void save(#Valid #RequestBody SaveRequest request) {
demoService.save(request);
}
In SaveRequest, I pass a single productUuid as shown below.
#Data
public class SaveRequest {
private UUID productUuid;
private DetailsRequest detailsRequest;
}
Here is my service method:
public void save(final SaveRequest request) {
detailService.getDetails(request.getProductUuid());
// code omitted
}
What I want to do is; I just want to pass productUuid as a list instead of single element. private List<UUID> productUuid;
I thought that I can call the service method for each productUuid in the SaveRequest, instead of modifying the service method by using a similar approach to the following. Then I call this methıd from the Controller instead of the save methof of the service.
public void saveList(final SaveRequest request) {
request.getProductUuidList().stream()
.map(this::save)
.collect(Collectors.toList());
}
But I could not use it. So, how should I fix this issue? If it is good approach to use saveList methood and call save method for each productUuid in the SaveRequest, it may be better to use it without changing the save method.
Updating the answer now. You were correct with your last answer, because Streams usually expect you to do something with what is inside (in your case UUIDs).
If you don't want to have a Consumer for UUIDs, you can use a for loop:
public void saveList(final SaveRequest request) {
for (UUID uuid: request.getProductUuidList()) {
save(request);
}
}
and if you need the UUID that is currently being iterated, change the save method to accept a UUID as an argument
public void saveList(final SaveRequest request) {
for (UUID uuid: request.getProductUuidList()) {
save(uuid, request);
}
}
As you can see, the last method has a consumer for UUIDs now, so it can also be done using streams:
public void saveList(final SaveRequest request) {
request.getProductUuidList().stream().forEach(
uuid -> save(uuid, request);
)
}
Using stream() here is optional, but can provide you with helpful features, such as filters.

Mocking with anonymous class in Java

I'm learning about dependecy injection and testing with Mockito. And I just found a tutorial where someone explain an application with dependency injection and without dependency injection. This is the link: https://www.journaldev.com/2394/java-dependency-injection-design-pattern-example-tutorial
I have 2 questions:
The first question is about the code that he writes for testing. What kind of mock is that? Don't you need to use #Mock to mock an object?
This is his code for testing:
public class MyDIApplicationJUnitTest {
private MessageServiceInjector injector;
#Before
public void setUp(){
//mock the injector with anonymous class
injector = new MessageServiceInjector() {
#Override
public Consumer getConsumer() {
//mock the message service
return new MyDIApplication(new MessageService() {
#Override
public void sendMessage(String msg, String rec) {
System.out.println("Mock Message Service implementation");
}
});
}
};
}
#Test
public void test() {
Consumer consumer = injector.getConsumer();
consumer.processMessages("Hi Pankaj", "pankaj#abc.com");
}
#After
public void tear(){
injector = null;
}
}
And the second question is about testing the app without dependency injection. I don't understand why he say that: "Testing the application will be very difficult since our application is directly creating the email service instance. There is no way we can mock these objects in our test classes." Why we cannot mock these objects in our test cases.
The first question is about the code that he writes for testing. What kind of mock is that? Don't you need to use #Mock to mock an object?
To mock an object you have to provide an object that has same type i.e behaves the same or is a subtype of the class that object you want to mock. So to mock an object you can use an instance of anonymous class (in your case it would be an object of anaonymous class that extends MyDIApplication) or you can use Mockito with its #Mock annotation which does basically similiar thing. Bascially using #Mock annotation is similiar to doing :
MyDIApplication myDiApplication = Mockito.mock(MyDIApplication.class)
which creates a mock object extending class passed in constructor. Here you may pass interface or class depending on what you want to mock.
When using anonymous class you provide implementation of methods that you want to mock in overriden implementations of methods, but in case of Mockito you provide intender behaviour by using methods like Mockito::when.
And the second question is about testing the app without dependency injection. I don't understand why he say that: "Testing the application will be very difficult since our application is directly creating the email service instance. There is no way we can mock these objects in our test classes." Why we cannot mock these objects in our test cases.
I guess you are refering to this piece of code :
public class MyApplication {
private EmailService email = new EmailService();
public void processMessages(String msg, String rec){
//do some msg validation, manipulation logic etc
this.email.sendEmail(msg, rec);
}
}
Here you create an instance of EmailService as class field. So there is no possibilty you can mock this (although you could use reflection or PowerMock). So you are tightly coupled to EmailService and it is hard to test MyApplication class logic. To be able to test it you can use constructor injection :
public class MyApplication {
private EmailService email;
public MyApplication(EmailService emaliService) {
this.email = emailService;
}
public void processMessages(String msg, String rec){
//do some msg validation, manipulation logic etc
this.email.sendEmail(msg, rec);
}
}
Or setter injection :
public class MyApplication {
private EmailService email;
public void setEmailService(EmailService emailService) {
this.email = emailService;
}
public void processMessages(String msg, String rec){
//do some msg validation, manipulation logic etc
this.email.sendEmail(msg, rec);
}
}

Mocking concrete class

I am unit testing a Presenter class which connects to service and returns a token
When user receives a token from Async task which calls REst services, Home screen starts. If token is null error is shown
public void onSignInButtonClicked() {
String username = mSigninView.getUsername();
if (username.isEmpty()) {
mSigninView.showUsernameError(R.string.username_error);
return;
}
String password = mSigninView.getPassword();
if (password.isEmpty()) {
mSigninView.showPasswordError(R.string.password_error);
return;
}
String token = mSigninService.connectToRestServices(username, password);
if (token != null) {
mSigninView.startHomeActivity(token);
} else {
mSigninView.showLoginError(R.string.login_error);
}
}
For unit testing :
#Test
public void shouldStartHomeScreenWhenUsernameAndPasswordAreCorrect() throws Exception {
Mockito.when(mView.getUsername()).thenReturn("test#test.com");
Mockito.when(mView.getPassword()).thenReturn("test");
Mockito.when(mService.connectToRestServices("test#test.com", "test")).thenReturn("test");
mPresenter.onSignInButtonClicked();
Mockito.verify(mView).startHomeActivity("test");
}
Error while testing
Wanted but not invoked:
signin_View.startHomeActivity("test");
-> at com.ssd.cypress.uimobile.SigninPresenterTest.shouldStartHomeScreenWhenUsernameAndPasswordAreCorrect(SigninPresenterTest.java:72)
In the code
String token = mSigninService.connectToRestServices(username, password);
It connects to concrete class and token is null. Is there a way to mock this connectToService so that it returns SomeValue.
Your mock service collaborator mService is never called during the test because it's not passed into or injected into the class under test. Based on your comments, I think you realize this.
To restate your comments as I understand them, you want to use the mock of a collaborator - an instance of Sign_in_service - but you can't do it because the collaborator is created by rather than passed into your class under test - SigninPresenter.
The problem is your constructor of SigninPresenter, which should not be responsible for creating a collaborator. It seems like you own the code in question, so you can change the design.
I suggest you replace the SigninPresenter constructor with the following:
public static SigninPresenter createSigninPresenterWithService(Signin_View view) {
return new SigninPresenter(view, new Sign_in_service());
}
protected SigninPresenter(Signin_View view, Sign_in_service service) {
mSigninView = view;
mSigninService = service;
}
For your test, you can call the constructor and pass in a mock of the service to initialize mPresenter, that is: mPresenter = new SignInPresenter(mView, mService). In your production code which currently calls the constructor of SigninPresenter, you can replace the constructor call new SigninPresenter(view) with a call to the static factory method createSigninPresenterWithService(view).

Getting PowerMockito to mock a static method on an Interface?

I have a library I am trying to mock for testing... There is a Java 8 interface with a static method implementation like this:
public interface Router {
public static Router router(Object param) {
return new RouterImpl(param);
}
}
And I am trying to mock that returned value:
PowerMockito.mockStatic(Router.class);
PowerMockito.doReturn(mockRouter).when(Router.router(any()));
But when I run the tests through a debugger, the mock instance is not returned.
I've tried a number of different permutations of the static mocking, but I cannot get the static method to return my mock value. Any thoughts?
You are doing it right, but we will have to wait when mocking static interface method is implemented/fixed in PowerMock. Watch this pull request:
https://github.com/jayway/powermock/issues/510
Note: Good news is that issue in Javassist is already fixed:
https://github.com/jboss-javassist/javassist/pull/11
Why not wrap it in an abstraction that you can mock?
class RouterFactory {
Router createRouter(Object param) {
return Router.router(param);
}
}
And use it in your class
class YourClass {
private final RouterFactory routerFactory;
YourClass(RouterFactory routerFactory) {
this.routerFactory = routerFactory;
}
void doSth() {
// do sth
}
}
Then you can mock the RouterFactory without any problems and you don't have to use Powermock.

How to test a Jersey rest service using mock objects

I have developed a rest service using Jersey. Now I want to write some integration tests for this web service but since not every class being used from the web service is already implemented I need to mock some of them. For example I have the following class:
public class A {
private String getWeather() {
return null;
}
}
My web service looks like this :
#Path("/myresource")
public class MyResource {
#GET
#Produces("text/plain")
public String getIt() {
A a = new A();
return a.getWeather();
}
}
The problem is that the getWeather function is not ready so I need to mock the return value for this function. But for the integration test where I issue a rest call I don't know how to do that.
Are there any ideas?
To make your design decoupled from A you should pass it in as a parameter to MyResource. Then you can easily mock it by hand or with mockito. With constructor injection it would look like this:
#Path("/myresource")
public class MyResource {
private A a;
public MyResource(A a) {
this.a = a;
}
#GET
#Produces("text/plain")
public String getIt() {
return a.getWeather();
}
}
and you can test it with
#Test
public void shouldGetIt() {
A a = mock(A.class);
when(a.getWeather()).thenReturn("sunny!");
MyResource r = new MyResource(a);
assertThat(r.getIt(), is("sunny!));
}
This makes your design decoupled. MyResource no longer depends on A directly but on anything that looks lik an A. Another benefit is that mockito doesn't mess with you class files. It is your code that is tested - not something that has been generated on the fly.
Many consider injection by constructor to be a bit old school. I am old so I like it.... With spring (a framework I don't recommend that you pick up) you can autowire variables like so:
#Autowire
private A a;
and you don't need the constructor at all. Spring will find a the only implementation of A and insert it in this variable. I prefer explicit programming so I would chose constructor injection any day.
You may be able to achieve this using Power Mockito (https://code.google.com/p/powermock/wiki/MockitoUsage)
#RunWith(PowerMockRunner.class)
#PrepareForTest({ MyResource.class })
public class MyResourceTest {
#Test
public void testGetIt()() {
MyResource mr = new MyResource();
//Setup mock
A mockA = PowerMockito.mock(A.class);
String mockReturn = "Some String";
//Stub new A() with your mock
PowerMockito.whenNew(A.class).withAnyArguments().thenReturn(mockA);
PowerMockito.doReturn(mockReturn).when(mockA).getWeather();
String ret = mr.getIt();
//asserts go here
}
}
Note that you can mock a local variable creation using PowerMockito's whenNew - this should take care of your concern for A a = new A() code in getIt() method.

Categories

Resources