PowerMock - Mock private method doesn´t work - spring-boot

I'm trying to mock a private method with PowerMock but the method I mock to always returns 0. I show you my classes to see if you can help me. Thank you.
Service.class
public int getNumber() { return getNumberPriv(); }
private int getNumberPriv() {
return 2;
}
ServiceTest.class
#SpringBootTest
#ActiveProfiles("test")
#RunWith(PowerMockRunner.class)
public class SharepointServiceTest {
#Test
public void fakeTest() throws Exception {
SharepointServiceImpl mock = PowerMockito.spy(new SharepointServiceImpl());
PowerMockito.doReturn(7).when(mock, "getNumberPriv");
int result = mock.getNumber(); //Always return 0
assertNotNull(result);
assertEquals(7, result);
}}

Probably something like you cannot mock calls to methods "within" the current class. There's no way to intercept the real call and hence no way to mock the response.

Related

Dependency injection with mockito example

I am very new with Mockito and I don't get the following example (classes were provided, only test to write) and how to solve it.
What I try to do is use a test double for the supplier so that we can control the returned greeting in the test and assert that the GreetingService does not modify the greeting message in any way. Then assert that the returned greeting string is equal to "Hello Andy.".
public class Greeting {
private final String template;
public Greeting(String template) {
this.template = template;
}
public String forName(String world) {
return String.format(template, world);
}
}
#Component
public class GreetingService {
private final Supplier<Greeting> greetingSupplier;
public GreetingService(Supplier<Greeting> greetingSupplier) {
this.greetingSupplier = greetingSupplier;
}
public String greet(String name) {
return greetingSupplier.get().forName(name);
}
}
#Component
public class RandomGreetingSupplier implements Supplier<Greeting> {
private final List<Greeting> greetings = Arrays.asList(
new Greeting("Hello %s."),
new Greeting("Hi %s!"),
);
private final Random random = new Random();
#Override
public Greeting get() {
return greetings.get(random.nextInt(greetings.size()));
}
}
#SpringBootTest
public class GreetingServiceTest {
#Autowired
GreetingService greetingService;
#MockBean
Supplier<Greeting> greetingSupplier;
#Test
void getGreetingForPerson() {
String name = "Andy";
// that test cannot know which greeting will be returned by the supplier
// WHY IS IT NULLPOINTEREXCEPTION AFTER INITIALIZING #MockBean
//String greeting = greetingService.greet(name);
//assertThat(greeting).contains(name);
// WROTE SUCH TEST HERE -> NullPointerException WHY?
Mockito.when(greetingSupplier.get().forName(name)).thenReturn("Hello %s.");
assertThat(greetingSupplier.equals("Hello Andy."));
// THIS IS WORKING & TEST PASSED BUT I GUESS ITS WRONG?
Mockito.when(greetingSupplier.get()).thenReturn(new Greeting("Hello %s."));
assertThat(greetingSupplier.equals("Hello Andy."));
}
}
Mockito.when(greetingSupplier.get().forName(name)).thenReturn("Hello %s.");
You can't chain calls like that, you need to produce intermediate results, like
Supplier<Greeting> supplier = mock(Supplier.class);
Mockito.when(supplier).forName().thenReturn("Hello %s.");
Mockito.when(greetingSupplier.get()).thenReturn(supplier);
For dependency injection, you need to create the subject under test with the mocked Supplier. You can do that in a #Before method for example.
Your mocking is wrong.
Mockito.when(greetingSupplier.get().forName(name)).thenReturn("Hello %s.");
You mocked Supplier<Greeting> and the default behavior is to return null. So when you call greetingSupplier.get() in your first line it returns null. You directly chain forName which nou basicall is null.forName which leads to an error.
Your second part is actually (kind of) correct.
Mockito.when(greetingSupplier.get()).thenReturn(new Greeting("Hello %s."));
You now properly return a response from greetingSupplier.get(). Instead of chaining the call.
However I would argue that your excercise is wrong. Why? When using a Supplier<?> in Spring it actually is a lazy beanFactory.getBean call. You can lazily inject dependencies this way. You should have a mock for Greeting which returns a hardcoded String which you can check.

Spring boot with Mockito mocking NamedParameterJdbcTemplate

Trying to unit test a method which is defined as :
public void myMethod(List<? extends MyModel> model){
int[] result = namedParameterJdbcTemplate.batchUpdate("update query", SqlParameterSourceUtils.createBatch(model));
}
In my test class i am defining test method as
class MyTestClass{
#Mock
NamedParameterJdbcTemplate namedParameterJdbcTemplate;
#InjectMocks
MyDao dao;
#Test
public void testMyMethod() {
final int[] rowsAffected = new int[]{1,2};
when(namedParameterJdbcTemplate.batchUpdate(any(), SqlParameterSourceUtils.createBatch(Arrays.asList(anySet())))).thenReturn(rowsAffected);
List<MyModel> myModels = new ArrayList<>();
MyModel mymodel = new MyModel();
mymodel.setSomeParam("");
myModels.add(mymodel);
dao.myMethod(myModels);
}
}
While running this test method , i am getting NullPointerException in called method(myMethod()). int[] result is coming as null. My understanding is it should get the result from the stub in the mock.
Please help me understand what am i doing wrong.
It seems that you're not using the correct import for any() because if it would be the correct ArgumentMatchers.any() from Mockito, Mockito would complain that you don't use an ArgumentMatcher for both parameters of .batchUpdate().
You can statically import it with import static org.mockito.ArgumentMatchers.*; or use ArgumentMatchers.any().
So as first step, try the following:
when(namedParameterJdbcTemplate.batchUpdate(ArgumentMatchers.any(), ArgumentMatchers.any())).thenReturn(rowsAffected);
or be less generic and match the return type of SqlParameterSourceUtils.createBatch() with:
// I don't know what SqlParameterSourceUtils.createBatch() returns, so you might have to adjust it
when(namedParameterJdbcTemplate.batchUpdate(ArgumentMatchers.any(), ArgumentMatchers.eq("SOME RETURN"))).thenReturn(rowsAffected);
It worked by adding the cast to the Argument matchers:
Updated Code :
when(namedParameterJdbcTemplate.batchUpdate(anyString(), (SqlParameterSource[]) any())).thenReturn(rowsAffected);

Value of doReturn not used

I use spring boot 2.
I search to test a private method in the facade
#RunWith(SpringRunner.class)
#SpringBootTest
public class SamplingsFacadeTest {
#Autowired
private SamplingsFacade facade;
#MockBean
private SamplingsService samplingsService;
#Test
public void exampleTest() throws Exception {
List<Samplings> samplings = new ArrayList<>();
Samplling sampling = new Samplings();
..
samplings.add(sampling);
//fake call
Mockito.doReturn(samplings).when(samplingsService.getSamplingContainingNonCompliantTest());
//real call
List<FactoryEmailNCDto> factoryEmails = Whitebox.invokeMethod(facade, "prepareDataNoncompliantSampling");
}
public List<Samplings> getSamplingContainingNonCompliantTest() {
return samplingsRepository.findSamplingContainingNonCompliantTest();
}
In Facade In
private List<FactoryEmailNCDto> prepareDataNoncompliantSampling() {
List<FactoryEmailNCDto> factoryEmailNC = new ArrayList<>();
List<Samplings> samplings = samplingsService.getSamplingContainingNonCompliantTest();
for (Samplings sampling : samplings) {
...
}
}
Why when I debug, samplings is null and not the value I created
Mockito.doReturn(samplings)
.when(samplingsService.getSamplingContainingNonCompliantTest());
One potential problem is that doReturn takes the form doReturn(value).when(mock).method(), not doReturn(value).when(mock.method()). The latter is considered an incomplete stubbing. Instead, it should look like this:
Mockito.doReturn(samplings)
.when(samplingsService)
.getSamplingContainingNonCompliantTest();
Note that there may be other problems with your test; the code you've written expects samplingsService to be public and non-final, and your getSamplingContainingNonCompliantTest() to likewise be public, non-static, and non-final, but the code sample you have does not confirm that. You may want to call Mockito.validateMockitoUsage() in an #After method, or use a #Rule that handles Mockito annotations and cleanup for you.

Verify a method is called inside a method without calling other methods inside that method

public class ServiceClass {
#Autowired
ConnClient connClient;
public void abc() {
result = connClient.query(arg1, arg2); // verify called once.
allDocsReturned = result.getResults(); // throws NPE
}
}
I need to verify that connClient.query(arg1,arg2) is called at least once. So in the test cases file i am calling the method abc()
#InjectMocks
ServiceClass serviceClass;
#Mock
ConnClient connClient;
#Test
public void testABC() {
serviceClass.abc();
verify(connClient, times(1)).query(arg1,arg2);
}
I get NullPointerException because of the line result.getResults() called above as result is null, and the test case getting failed.
Please help.
You need to mock the call to connClient.query and ResultSet:
#InjectMocks
ServiceClass serviceClass;
#Mock
ConnClient connClient;
#Test
public void testABC() {
ResultSet rs = mock(ResultSet.class);
when(rs.getResults()).thenReturn(//here return the object of type of your variable allDocsReturned);
when(connClient.query(arg1,arg2)).thenReturn(rs);
serviceClass.abc();
verify(connClient, times(1)).query(arg1,arg2);
}
Your class ConnClient is a mock which is why the call connClient.query(arg1, arg2) will return null ad thus a NPE is thrown when dereferencing the result.
In this case you can specify the return value of the method call, i.e.
doReturn(someObject).when(connClient).query(arg1,arg2);
where someObject is allowed to be a mock (alternatively, you can return a concrete value).
Once this is done, result won't be null anymore and no NPE will be thrown.
Note that if result is dereferenced later, you also have to mock the getResults() call.
Edit:
#InjectMocks
ServiceClass serviceClass;
#Mock
ConnClient connClient;
#Mock
Result result;
#Test
public void testABC() {
doReturn(result).when(connClient).query(arg1,arg2);
serviceClass.abc();
verify(connClient, times(1)).query(arg1,arg2);
}
Now result will not be null, however, allDocsReturned will still be null, but will not lead to a NPE with the code posted by you

Is a mock MongoRepository saving objects?

I am using SpringBoot 1.5.9 and try to do Integration testing. Weirdly a MongoRepository.save() method updates the object when called on mock MongoRepository.
I have a Counter Class
public class Counter {
public String id;
public int seq;
public void increaseSeq() {
this.seq += 1;
}
}
And his repository
public interface CounterRepository extends MongoRepository<Counter, String>{
Counter findById(String id);
List<Counter> findAll();
}
And his service
#Service
public class CounterService {
#Autowired private CounterRepository counterRepository;
public Counter findCounter(String id) {
return counterRepository.findById(id);
}
public int getSeqAndIncrease(String id) {
Counter counter = findCounter(id);
if (counter == null) {
return -1;
}
counter.increaseSeq();
counterRepository.save(counter);
return counter.getSeq();
}
}
Now, when I do system integration and try to mock the counterRepository, it happens something that I don't expect. The counterRepository.findById() returns a Counter object where the 'seq' field is increased. Why? Does the counterRepository.save() affect the result in any way (the counterRepository is mocked, hence I suppose that save() should not have any effect)?
#RunWith(SpringRunner.class)
#SpringBootTest
public class FlowServiceTest {
#MockBean private CounterRepository counterRepository;
#Autowired private CounterService counterService;
#Before
public void setUp() {
Mockito.when(counterRepository.save(any(Counter.class))).then(arg -> arg.getArgumentAt(0, Counter.class));
Mockito.when(counterRepository.findById("flow")).thenReturn(new Counter("flow", 10));
}
#Test
public void testSavingInDatabase() {
System.out.println(counterRepository.findById("flow"));
counterService.getSeqAndIncreaseSafe("flow");
System.out.println(counterRepository.findById("flow"));
counterService.getSeqAndIncreaseSafe("flow");
System.out.println(counterRepository.findById("flow"));
}
}
It prints "10 11 12". Why doesn't it print '10 10 10'?
The problem is these lines
counterRepository.save(counter);
return counter.getSeq();
What you should be doing is this
Counter saveCounter = counterRepository.save(counter);
return savedCounter.getSeq();
In getSeqAndIncrease method, you are not returning sequence of the saved object.
By doing this you are making your mock statement for save useless. Because you are not using the value returned from mock.
tl;dr - The returned object from mock is initialized only once in mockito. So I basically got the same reference every time, and since it is a reference not a new object, the values are updated.
Complete answer: When setting
Mockito.when(counterRepository.findById("flow")).thenReturn(new Counter("flow", 10));
, it might seem intuitive to return a new object every time, but the return object is initialised only once when the test starts and will be returned at all subsequent calls.
Then, in my code I do
counter.increaseSeq();
which increases the 'seq' of found object (this object comes from Mockito). Then at the next call, Mockito returns the firstly initialised object which was updated in the meantime; Mockito does not return a new object as it might seem like.

Resources