Test a method which calls another method of the object in mockito - java

I have an interface, ex:
interface MyService {
void createObj(int id)
void createObjects()
}
I want to test an implementation of the createObjects method, which has body like:
void createObjects() {
...
for (...) {
createObj(someId);
}
}
I have already tested createObj(id):
#Test public void testCreate() {
//given
int id = 123;
DAO mock = mock(DAO.class);
MyService service = new MyServiceImpl(mock);
//when
service.createObj(id);
//verify
verify(mock).create(eq(id));
}
So I don't want to repeat all test cases for it in the test for createObjects.
How can I make sure that another method of the real object was called besides the one I am testing?

Use a spy:
MyService myService = new MyServiceImpl()
MyService spy = spy(myService);
doNothing().when(spy).createObj(anyInt());
// now call spy.createObjects() and verify that spy.createObj() has been called
This is described, like everything else, in the api doc.

Related

Mockito - Spying on more than one dependency

Is it possible to inject a spy for two dependencies into the tested class?
I have this class:
#Service
#Singleton
#MessageReceiver
public class LinkHitCallbackEventHandler {
public static final Logger logger = LogManager.getLogger();
#Inject
private CallbackInvocationBuilder callbackInvocationBuilder;
#Inject
private CallbackLogBuilder callbackLogBuilder;
#MessageReceiver
public void handle(#SubscribeTo LinkHitEvent event) {
Entity<Form> entity = EntityFormFactory.createFromEvent(event);
this.callbackLogBuilder.build(entity);
Response response = this.callbackInvocationBuilder.post(entity);
}
}
Importantly, it's a simple class with two injected dependencies: callbackInvocationBuilder and callbackLogBuilder.
I test calls to these dependencies in the following way:
#Test
public void send_callback_after_event_is_published() {
target("/testY")
.property("jersey.config.client.followRedirects", false)
.request()
.header("User-Agent", UserAgentMother.allowedUserAagent())
.get();
verify(callbackInvocationBuilder).post(anyObject());
// verify(callbackLogBuilder).build(anyObject());
}
This arrangement the test passes, because I first call callbackLogBuilder.build(entity).
If I swap calls and call them first callbackInvocationBuilder.post(entity), the test will fail.
Both callbackLogBuilder and callbackInvocationBuilder are spies. I configure them in configure () from JerseyTest. In exactly the same way.
One of the method to inject spy to use whitebox and use verify
like this:
Whitebox.setInternalState(ClassToTest.class, "Object", spy1);
, So the test method ill be like this:
#Test
public void send_callback_after_event_is_published() {
Whitebox.setInternalState(LinkHitCallbackEventHandler.class, "callbackInvocationBuilder", spy1);
Whitebox.setInternalState(LinkHitCallbackEventHandler.class, "callbackInvocationBuilder", spy2);
target("/testY")
.property("jersey.config.client.followRedirects", false)
.request()
.header("User-Agent", UserAgentMother.allowedUserAagent())
.get();
verify(callbackInvocationBuilder).post(anyObject());
verify(callbackLogBuilder).build(anyObject());
}
, If you want to capture the argument
ArgumentCaptor<Entity> captor = ArgumentCaptor.forClass(Entity.class);
verify(callbackInvocationBuilder, times(1)).post(captor.capture());
Entity actualEntity = captor.getValue();
assertEquals(expected, actualEntity);

Test if another method is called from a class using JUnit or Mockito

I have a class like this
public class LoginPresImpl implements LoginAPIInterface.LoginDataListener, LoginAPIInterface.LoginPresenter{
LoginAPIInterface.LoginView loginView;
LoginAPIInterface.LoginDataInteractor loginDataInteractor;
public LoginPresImpl(LoginAPIInterface.LoginView loginView) {
this.loginView = loginView;
loginDataInteractor=new LoginDataModel(this);
}
#Override
public void getLoginUpdateData(String username, String password,String registrationToken) {
loginDataInteractor.getLoginData(username,password,registrationToken);
}
}
I want to test if calling
getLoginUpdateData()
will call the getLoginDate() method of loginDataInteractor.
I have created a test class like this
public class LoginPresImplTest {
LoginAPIInterface.LoginDataInteractor loginDataInteractorMock;
LoginAPIInterface.LoginView loginViewMock;
LoginPresImpl loginPres;
#Before
public void setUp(){
loginDataInteractorMock = Mockito.mock(LoginAPIInterface.LoginDataInteractor.class);
loginViewMock = Mockito.mock(LoginAPIInterface.LoginView.class);
loginPres = Mockito.spy(LoginPresImpl.class);
}
#Test
public void getLoginUpdateData() {
loginPres.getLoginUpdateData("01","","");
verify(loginPres).getLoginUpdateData("01","","");
}
But I don't know how to check if calling
getLoginUpdateData()
will eventually call
loginDataInteractor.getLoginData()
method. How can I test this using JUnit or Mockito.
I want to test if calling
getLoginUpdateData()
will call the getLoginDate() method of loginDataInteractor.
loginDataInteractor is a dependency of the code under test (cut) you showed.
In a UnitTest you only verify the behavior of the cut. You do not verify the behavior of the dependencies. They get their own unit tests.

EasyMock - mock object returned from new Object

Is it possible, with a capture for example, to return a mock when a method is called from a new object?
To make it more concrete:
SecurityInterface client = new SecurityInterface();
port = client.getSecurityPortType(); --> I want to mock this.
easymock version: 3.3.1
Yes, if you also use Powermock your test code can intercept the calls to new and return a mock instead. So you can return a mock for new SecurityInterface() and then mock its getter
Powermock is compatible with Easymock
#RunWith(PowerMockRunner.class)
#PrepareForTest( MyClass.class )
public class TestMyClass {
#Test
public void foo() throws Exception {
SecurityInterface mock = createMock(SecurityInterface.class);
//intercepts call to new SecurityInterface and returns a mock instead
expectNew(SecurityInterface.class).andReturn(mock);
...
replay(mock, SecurityInterface.class);
...
verify(mock, SecurityInterface.class);
}
}
No - this is exactly the sort of static coupling that you need to design out of your classes in order to make them testable.
You would need to provide the SecurityInterface via a supplier or a factory which you inject: you can then inject an instance which invokes new in your production code, and an instance which returns a mock in your test code.
class MyClass {
void doSomething(SecurityInterfaceSupplier supplier) {
Object port = supplier.get().getSecurityPortType();
}
}
interface SecurityInterfaceSupplier {
SecurityInterface get();
}
class ProductionSecurityInterfaceSupplier implements SecurityInterfaceSupplier {
#Override public SecurityInterface get() { return new SecurityInterface(); }
}
class TestingSecurityInterfaceSupplier implements SecurityInterfaceSupplier {
#Override public SecurityInterface get() { return mockSecurityInterface; }
}

Unit testing Amazon SWF child workflows

I have a parent workflow (ParentWorkflow) calling a child workflow (ChildWorkflow) and I'm trying to test out the call.
The parent code looks something like this:
public class ParentWorkflow {
private final ChildWorkflowClientFactory childWorkflowClientFactory =
new ChildWorkflowClientFactoryImpl();
public void runWorkflow() {
new TryCatch() {
#Override
protected void doTry() throws Throwable {
Promise<Void> workflowFinished = childWorkflowClient.childWorkflow(x);
...
}
...
}
}
I want to mock out the
childWorkflowClient.childWorkflow(x)
call, however when I am hooking up the unit test I don't appear to have the option to inject the client factory, the unit test code looks like this:
#Rule
public WorkflowTest workflowTest = new WorkflowTest();
#Mock
private Activities mockActivities;
private ParentWorkflowClientFactory workflowFactory
= new ParentWorkflowClientFactoryImpl();
#Before
public void setUp() throws Exception {
// set up mocks
initMocks(this);
workflowTest.addActivitiesImplementation(mockActivities);
workflowTest.addWorkflowImplementationType(ParentWorkflowImpl.class);
workflowTest.addWorkflowImplementationType(ChildWorkflowImpl.class);
I don't appear to be able to pass anything into the workflow implementation classes, is there another way I can mock the child workflow out?
You can test workflow code directly mocking its dependencies without using workflowTest:
/**
* Rule is still needed to initialize asynchronous framework.
*/
#Rule
public WorkflowTest workflowTest = new WorkflowTest();
#Mock
private ActivitiesClient mockActivities;
#Mock
private BWorkflowClientFactory workflowFactory;
#Before
public void setUp() throws Exception {
// set up mocks
initMocks(this);
}
#Test
public void myTest() {
AWorkflowImpl w = new AWorkflowImpl(workflowFactory);
w.execute(); // whatever execute method of the workflow
}
This approach allows testing parts of the workflow encapsulated in other objects instead of the entire workflow.
If for whatever reason (for example you are using other testing framework than JUnit) you don't want to rely on WorkflowTest #Rule asynchronous code can be always executed using AsyncScope:
#Test
public void asyncTest() {
AsyncScope scope = new AsyncScope() {
protected void doAsync() {
// Any asynchronous code
AWorkflowImpl w = new AWorkflowImpl(workflowFactory);
w.execute(); // whatever execute method of the workflow
}
};
scope.eventLoop();
}
EDIT: The below only applies to SpringWorkflowTest; WorkflowTest doesn't have addWorkflowImplementation for some reason.
The correct way to use the WorkflowTest would be to add a mock implementation for the child workflow rather than adding the actual type:
#Rule
public SpringWorkflowTest workflowTest = new SpringWorkflowTest();
#Mock
private Activities mockActivities;
#Mock
private ChildWorkflow childWorkflowMock;
private ParentWorkflowClientFactory workflowFactory
= new ParentWorkflowClientFactoryImpl();
#Before
public void setUp() throws Exception {
// set up mocks
initMocks(this);
workflowTest.addActivitiesImplementation(mockActivities);
workflowTest.addWorkflowImplementationType(ParentWorkflowImpl.class);
workflowTest.addWorkflowImplementation(childWorkflowMock);
...
}
The framework will then call this mock instead of the actual implementation when you use the factory.

why is mockito not called when executing mocked method?

Here is my test:
#Test
public void myTest() throws Exception {
String aVenueId = "1.2.3";
Venue2 aVenue = new Venue2(aVenueId);
VenuesRepository repository = mock(VenuesRepository.class);
when(repository.getVenue(anyString())).thenReturn(new VenueThumb(aVenue));
aMethodWithInnerCallToRepositoryGetVenue();
...
}
However when test runs my real code,
this line returns null (as there is no venue with venueId = "1.2.3"
that's why i used my mock for the first place).
public void aMethodWithInnerCallToRepositoryGetVenue(){
...
IVenue v = repository.getVenue(r.venueId);
..
}
You mocked a repository in your method, but this mock repository is assigned to a local variable only. So the code calling repository.getVenue() calls it on a different repository instance, and not on the one created by Mockito:
aMethodWithInnerCallToRepositoryGetVenue();
There's no way this method knows about the local variable initialized just before the method call.
As the user JB Nizet has written you are using two different instances of repository. You can do something like this: first you have a repository class you want to mock being a collaborator in the next class.
public class VenuesRepository {
public IVenue getVenue(String id) {
return new IVenue() {
// do something
};
}
}
Class Foo uses an instance of VenuesRepository as a collaborator which is not the objective of your unit test so you should mock its behavior when required.
public class Foo {
private VenuesRepository repository;
public Foo(VenuesRepository repo) {
repository = repo;
}
public IVenue getVenueFromRepository(String id) {
return repository.getVenue(id);
}
}
Now the test
public class FooTest {
#Test
public void testGetRepositoryWithMock() throws Exception {
String aVenueId = "1.2.3";
VenuesRepository repository = mock(VenuesRepository.class);
when(repository.getVenue(anyString())).thenReturn(mock(IVenue.class));
Foo foo = new Foo(repository);
assertNotNull(foo.getVenueFromRepository(aVenueId));
}
}
Now the instance of repository which has been mocked is the same.
I hope it helps.

Categories