Mock Method of authowired bean using mockito and spring mock - java

I have to impelement a test for MyService that conntain two methods method1 & method2:
and the method1 call method2 (method1 --> method2 )
so i've somthing like this in my test class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = SpringBootApplicationTest.class)
#ContextConfiguration(classes = { conf.class })
public class CommonCAMServiceTest {
#Autowired
private MyService myService;
test_method_1(){...}// this is what i want to implement and i have to mock the method2 call
test_method_2(){...}//this work fine
...
so i want to test my method1 but with the mock of method ( even my service class is autowired not mocked)
Thanks

Mockito supports what I will call "partial mocking";
it is called Spy.
Instead of creating a mock bean for your service,
create a Spy.
Also,
as mentioned in other answers,
don't user #Autowire for the service.
Here is some example code:
public class CommonCAMServiceTest
{
#Spy
private MyService myService;
#Before
public void before()
{
MockitoAnnotations.initMocks(this);
// Mock method2 for every test.
doReturn(something).when(myService).method2();
}
#Test
public void someTestName()
{
// Mock method2 in this test.
doReturn(somethingElse).when(myService).method2();
... call method1 to do stuff.
}
}

Create two Services for those two Methods. Then you can mock one service to test the other.

Lets assume that your Service look like that:
#Service
public class MyService {
public void method1() {
method2();
}
public void method2() {
System.out.println("calling method 2");
}
}
So if you willing to Mock the method2 function you we'll need to use a Mocked Bean for that using Spring & Mockito
#MockBean // Use that instead of #Autowired, will create a Mocked Bean
public MyService service;
#Test
public void testing() {
Mockito.doAnswer((Answer<Void>) invocation -> {
System.out.println("mocked");
return null;
}).when(service).method2();
Mockito.doCallRealMethod().when(service).method1();
service.method1();
}

Related

Spring injecting an initiallized mock via constructor

I have a singleton class (so private constructor) which needs to use a Spring Data repository during initialization. I have one injected as a constructor argument. Roughly:
#Controller
public class MyClass {
#Autowired
private MyClass(MyRepository repo) {
repo.findAll();
}
}
I want to unit test my class, so I need to have a mock repository initialized with mock values and then passed into my class before my class is initialized. How do I write my Mockito mocks in my JUnit test to make this possible?
You don't need Spring; this is an advantage of constructor injection. Just use MyRepository mockRepo = mock(MyRepository.class) and new MyClass(mockRepo).
(Your constructor should be public, by the way. You seem to be making the common mistake of confusing different senses of "singleton"; in the case of DI it simply means that the container only makes a single instance and shares it. Finally, if you only have one constructor you don't need #Autowired.)
Unit test should be independent. It means, we are not using real data from database even call any service from our test file.
Assuming you are using JUni5 and have findAllStudents() in your controller. So your test file approximately like this
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MyClassTest {
#Mock
private MyRepository repo;
#InjectMocks
private MyClass controller;
#BeforeAll
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testDataIsExist() {
List<String> expectednames = new ArrayList();
expectedNames.add("Foo");
expectedNames.add("Bar");
Mockito.when(myRepo.findAll()).thenReturn(expectedNames);
List<String> result = controller.findAllStudents();
Assertions.assertNotNull(result);
Assertions.assertEquals(expectednames, result);
}
}
So we are mock all the services we use in controller, then inject to controller itself. Then inside the test method we mock repo.findAll() to return expectedNames so if the controller find that function it will return what mock says to return.
After we call the function, we have to make it sure that the result is according to what we expected.
There is little value in a "unit test" for a #Controller implementation. If you use #WebMvcTest, then you can use #MockBean:
#WebMvcTest
class MyControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private MyRepository repository;
#Test
void testSomething() {
mockMvc.perform( ... );
}
}

mockito spy does not work on a factory bean method

I have a springboot that I am writing unit test for. There is a factoryBean out of which I get service object in runtime. I want to test that a specific method on this service object is invoked. Here is the app code
#Component
public class AppClient {
#Autowired
ServiceFactory factory
Service secretService
#postContruct
public void init(){
this.secretService=factory.get("secret");
}
public void process(Map<String, Object> param){
for (String key: param.keySet()){
if (key.equals("foobar")){
restService.handle(param.get(key));
}
}
}
}
Here is the unit test I have
#RunWith(SpringRunner.class)
#SpringBootTest
public class AppTest {
#Autowired
AppClient appClient;
#SpyBean
ServiceFactory factory;
Service secretService;
#Before
public void init(){
this.secretService=Mockito.spy(factory.get("secret"));
}
#Test
public void testProcess() {
Object obj = new MyDummyObject();
Map<String, Object> params = new HashMap<>();
params.put("foobar", obj);
appClient.process(params);
Mockito.verify(secretService).handle(obj);
}
}
The test fails and when I run through debugger, I see that handle is invoked. so what is wrong here?
EDIT
#MockBean
ServiceFactory factory;
#Mock
Service secretService
#Before
public void init(){
Mockito.when(factory.get(eq("secret"))).thenReturn(secretService);
}
with this change, factory bean is mocked but secretService is null inside in AppClient. that is, secretService is not being stubbed in. tested through debugger.
The PostConstruct callback executes before the spring application entirely runs and before your test-class make some preparations on the mock of the factory. You can't be able to declare Mockito when().then() expectations on the code which runs in the PostConstruct callback.
I can suggest you make a constructor based injection in the AppClient bean:
#Component
public class AppClient {
private final ServiceFactory factory
#Autowired
public AppClient(ServiceFactory factory){
this.factory = factory;
}
...
}
and test this as a simple unit-test. By manually creating an instance of the AppClient, injecting a mock of the factory, execute the init method and verifying all that you need:
#Test
void initTest(){
when(factory.get(..)).thenReturn(..);
AppClient client = new AppClient(factory);
client.init();
verify(..)
}

Mockito: mocking a method of same class called by method under test when using #InjectMocks

I have a class I want to test that has several external dependencies, and a couple internal methods. I would like to write a test for MethodA, but not have Method A's internal call to MethodB to actually exercise MethodB. I'd like to mock/stub MethodB and return something specific instead. Usually I'd use when/thenReturn but it doesn't behave like I expect - it actually jumps into Method B while creating the mock itself.
MyService.java
#Service
public class MyService {
#Autowired
private ServiceA serviceA;
#Autowired
private ServiceB serviceB;
public SomeObject methodA() {
// some logic using serviceA.method and serviceB.method that creates "output"
SomeObject someObject = methodB(output);
return someObject;
}
public SomeObject methodB(SomeObject someObject) {
// deep mysteries done here to someObject
return someObject
}
}
MyServiceTest.java
public class MyServiceTest {
#Mock
private ServiceA serviceA;
#Mock
private ServiceB serviceB;
#InjectMocks
private MyService myService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void methodATest() {
when(serviceA.method()).thenReturn(stuff);
when(serviceB.method()).thenReturn(otherStuff);
// here is what I would like to do
when(myService.methodB()).thenReturn(mockedSomeObject); //<- doesn't work
assertThat(myService.methodA().getSomeObjectProperty())
.isEqualTo("property");
}
}
I've looked at solutions that manually mock the MyService class with Mockito.mock(MyService.class), but (as the above example is obviously contrived) my actual class has quite a few external dependencies and I'd prefer a solution that still allows me to mock the service using #Mock for the #Autowired dependencies and #InitMocks for the class under test, unless it's simply not possible.
I've tried:
Mockito.doReturn(mockedSomeObject).when(myService.methodB(any(SomeObject.class));
but that also steps into MethodB when creating the mock for that method, which shouldn't be happening.
Thanks in advance for the help!
Try Adding #Spy to your InjectMocks and use the object to "expect" them in a slightly different syntax.
import org.mockito.Spy;
#InjectMocks
#Spy
private MyService myService;
And now mock the service call
Mockito.doReturn(mockedSomeObject).when(myService).methodB();
Also change the other mock call to this
Mockito.doReturn(stuff).when(serviceA).method();
Mockito.doReturn(otherStuff).when(serviceB).method();
You need to mark your object as Spy or explicitly create a Spy object for it using MyClass objA=null;
MyClass spy_objA=Powermockito.spy(objA)
doReturn(what_you_want).when(spy_objA).method()
Edit: Can find a similar question you may want to check
How to mock another method in the same class which is being tested?

mock resource in service java (mockito)

I am doing some tests for the class Export
I need to mock a method so I made a mockito (I am new to Mockito)
public Class ExportServiceImpl implements ExportService{
#Autowired
Service service
public void export(){
String exportString = service.getPath();
domoreStuff() ....
}
And
public Class ServiceImpl implements Service(){
public String getPath(){
return "thePath";
}
}
I need to mock the getPath() method so I did in the TestNG
public class ExportTestNG(){
public textExport(){
Service serviceMock = Mockito.mock(Service.class);
Mockito.when(serviceMock.getData()).thenReturn("theNewPath");
System.out.println("serviceMock.getData() : " + serviceMock.getData()); // prints "theNewPath", OK
exportService.export(); // the getData() is not the mockito one
}
}
I may have not correclt mockito and I may not have understood how it works.
Any idea ?
You can use Mockito to inject the mocks for you and avoid having to add setter methods.
#RunWith(MockitoJUnitRunner.class)
public class ExportTestNG(){
#InjectMocks
private ExportServiceImpl exportService;
#Mock
private Service serviceMock;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
public textExport(){
Mockito.when(serviceMock.getData()).thenReturn("theNewPath");
exportService.export();
}
}
You need to wire the mock service into the exportService object.
If you have a setter for the service member variable then do this:
exportService.setService(serviceMock);// add this line.
exportService.export();
If you don't have a setter you will need to perform the wiring before calling export.
Options for this include:
Set the value of the service member variable using reflection.
Write a test-only version of the Service and use a test-only version of the spring configuration xml files.
Something else (that I have never done and thus don't know about).

How to mock a private dao variable?

I have a dao.create() call that I want to mock when testing a method.
But I am missing something as I'm still getting NPE. What is wrong here?
class MyService {
#Inject
private Dao dao;
public void myMethod() {
//..
dao.create(object);
//
}
}
How can I mock out the dao.create() call?
#RunWith(PowerMockRunner.class)
#PrepareForTest(DAO.class)
public void MyServiceTest {
#Test
public void testMyMethod() {
PowerMockito.mock(DAO.class);
MyService service = new MyService();
service.myMethod(); //NPE for dao.create()
}
}
You are not injecting the DAO. With mockito you can change your test class to use #InjectMocks and use mockito runner.
#RunWith(MockitoJUnitRunner.class)
public void MyServiceTest {
#Mock
private Dao dao;
#InjectMocks
private MyService myService;
...
}
You can read more about InjectMocks at Inject Mocks API
Simpler way is changing your injection to injection by constructor. For example, you would change MyService to
class MyService {
...
private final Dao dao;
#Inject
public MyService(Dao dao) {
this.dao = dao;
}
...
}
then your test you could simple pass the mocked DAO in setup.
...
#Mock
private Dao dao;
#Before
public void setUp() {
this.dao = mock(Dao.class);
this.service = new MyService(dao);
}
...
now you can use verify to check if create was called, like:
...
verify(dao).create(argThat(isExpectedObjectBeingCreated(object)));
}
private Matcher<?> isExpectedObjectBeingCreated(Object object) { ... }
Using injection by constructor will let your dependencies clearer to other developers and it will help when creating tests :)
You still need to set the dao field with your mock.
You can use reflection to this.
You need to inject/set the mocked object DAO in your service class.
If it is a spring based project, you may have a look # Spring Junit Testrunner
If you use new MyService() the Dao is never injected. For the Dao to be injected you need to load the MyService via an ApplicationContext (Spring) or an Injector (Guice). Like you would in your normal application.
As others have already said, you need to set the dao field in your MyService class in some fashion. I'm unsure the mechanism to allow for a compound runner on your test to use both Powermock and a DI framework runner (assuming Powermock is required), but as long as you're already using PowerMock (for reasons unclear in the given example), you could avail yourself of the Whitebox class to set the dao more manually.
public void testMyMethod() {
Dao dao = mock(Dao.class)
doNothing().when(dao).create(anyObject())); //assuming no return val for dao.create()
MyService service = new MyService();
Whitebox.setInternalState(service, "dao", dao);
service.myMethod();
}

Categories