Mock local variable in Junit, Mockito - java

I'm working on a test case for a code using Mockito. The code looks like this,
public class Example {
#Autowired
private HelperService hs;
public void someMethod() {
List<String> names = new ArrayList<>();
hs.addValues(names);
if(names.size() < 5) {throw new RuntimeException("Invalid names list");}
return;
}
}
public class HelperService {
public void addValues(List<String> names) {
names.add("alex");
names.add("harry");
names.add("james");
names.add("maria");
names.add("bob");
}
}
I know this is a contrived example but I have a similar usecase where I cannot modify the existing code. I want to unit test the Example class using Junit, Mockito. How can I test the exception scenario where names.size() is < 5.

I'm going to assume you already have a means for setting the HelperService field in your test (whether that's by making it a #SpringBootTest, using #InjectMocks, or something else). So this will just give options for providing one that will let you do what you want:
Extend HelperService and inject that:
// Inject this into your class under test
private HelperService hs = new LessThan5NameAddingHelperService();
class LessThan5NameAddingHelperService extends HelperService {
#Override
public void addNames( List<String> names ) {
names.add( "Dave" );
}
}
Provide a mock HelperService which does the same:
// Inject this into your class under test
private HelperService hs;
#Before
public void setupMockHelperService() {
hs = mock( HelperService.class );
doAnswer( invocation -> {
List<String> names = ( List<String> ) invocation.getArguments()[0];
names.add( "Dave" );
return null;
} ).when( hs ).addNames( any() );
}

Related

In Java, How to test void method in Junit Mockito with assertion?

How to test void methods in Mockito with assertSame or assertEquals. I am able to do verify only.
i am getting sonar or PMD rules violation -"JUnit tests should include assert() or fail()".
Below is my sample class with test class.
#Service
public class MyServiceImpl implements IService {
#Autowired
private IDyDBDAO dyDBDAO;
#Override
public void update() {
dyDBDAO.save(getDetailData());
}
#Override
public List<Detail> getCurrentDetail() {
return getDetails(dyDBDAO.findAll());
}
private List<Detail> getDetails(Iterable<Detail> details) {
...blah...
}
private String getPlace(){
Places p = Places.getPlace();//static
return p == null? PlacesUtil.getName("DH"): p.getName;
}
private Detail getDetailData() {
Detail d = new Detail();
d.setName("blah");
d.setDesc("fsdfsdfdsf");
d.setPlace(getPlace());
return d;
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest({Places.class, PlacesUtil.class})
public class MyServiceImplTest {
#InjectMocks
private MyServiceImpl myServiceImpl;
#Mock
private IDyDBDAO dyDBDAO;
#Test
public void testGetCurrentDetail() {
given(dyDBDAO.findAll()).willReturn(getMockDetails());
assertSame(myServiceImpl.getCurrentDetail().size(), 2);
}
#Test
public void testUpdate() {
PowerMockito.mockStatic(Places.class);
// first update , second update -us-west-2 will update
given(Places.getPlace()).willReturn(PlacesUtil.getName("UH"))
.willReturn(null);
myServiceImpl.syncStatus();
// update again with DH
myServiceImpl.syncStatus();
verify(dyDBDAO, times(2)).save(any(Detail.class));
// how to assert checking here
}
private Iterable<Detail> getMockDetails() {
Detail d1 = new Detail();
d1.setName("blah");
d1.setDesc("fsdfsdfdsf");
d1.setPlace("sdfsdf");
Detail d2 = new Detail();
d2.setName("blahblah1");
d2.setDesc("e345345");
d2.setPlace("8907j");
List<Detail> listOfDetail = new ArrayList<>();
listOfDetail.add(eps1);
listOfDetail.add(eps2);
return listOfDetail;
}
}
You need to capture the value passed to the dao save method. Use mockito's ArgumentCaptor for that. Then assert on that value.
Something along these lines:
ArgumentCaptor<Detail> captor = ArgumentCaptor.forClass(Detail.class);
verify(dyDBDAO, times(2)).save(captor.capture());
Detail detail1 = captor.getValues().get(0)
assertEquals(expectedDetail, detail1)
I would assume that your void method that needs to be tested is update in MyServiceImpl.
Firstly, you can verify if dyDBDAO.save() is called.
Mockito.verify(dyDBDAO).save(Mockito.anyList...);
Secondly, you can check the modified or created records in the database by retrieving them and comparing to the inputs from getMockDetails.

Mockito ArgumentCaptor does not return any values on verification

I am trying to use argument capture to determine what arguments are being passed to a mocked Mockito method, but I am not able to capture any values.
class CombinedEvent
{
final List<String> events;
public CombinedEvent() {
this.events = new ArrayList<>();
this.events.add("WATCHITM");
this.events.add("BIDITEM");
}
}
Holder class
class CombinedNotificationAdapter {
private CombinedEvent combinedEvent;
CombinedNotificationAdapter() {
this.combinedEvent = new CombinedEvent();
}
public boolean isEnabled(String user, NotificationPreferenceManager preferenceManager) {
boolean status = true;
for (String event : combinedEvent.events) {
status = status && preferenceManager.isEventEnabled(user, event);
}
return status;
}
}
My unit test
#RunWith(JUnit4.class)
class CombinedNotificationAdapterTest {
private CombinedNotificationAdapter adapter;
#Mock
private NotificationPreferenceManager preferenceManager;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
adapter = new CombinedNotificationAdapter();
}
#Test
public void testIsEnabled() {
doReturn(true).when(preferenceManager).isEventEnabled(eq("test"), anyString());
Assert.assertTrue(adapter.isEnabled("test", preferenceManager));
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(preferenceManager, times(2)).isEventEnabled(eq("test"), captor.capture());
System.out.println(captor.getAllValues());
}
}
The output of captor.getAllValues() is an empty list. I would like the values to return a list of WATCHITM and BIDITEM. I don't know what I am going wrong.
Reference:
https://static.javadoc.io/org.mockito/mockito-core/2.28.2/org/mockito/Mockito.html#15
https://static.javadoc.io/org.mockito/mockito-core/2.6.9/org/mockito/ArgumentCaptor.html
I think you are overdoing:
doReturn(true)
. when(preferenceManager)
.isEventEnabled(eq("test"), anyString()):
You are scrubbing that expected method invocation and then combining that with your argument captor. And that does not work. You can either stub or capture, not both things! See this existing question for example.
My suggestion: look at this answer and learn how to create your own Answer object. Those get passed an instance of InvocationOnMock. And that class allows you to check the arguments passed into the mocked calls, too!

Mocking a DAO in Mockito

I'm just getting into testing of code. I have done unit tests before but haven't really isolated them. So they were more like integration test (indirectly). I want to give Mockito a try and I have added it to my Intellij IDE.
But I have no idea of how to actually implement mocking at all. There are examples on their website but I just can't wrap my head around the concept of mocking. I know that one uses mocking to isolate the unit testing to ensure that the errors are in the unit itself and not in a dependency.
I wrote the following:
#Test
public void testChangeMemberReturnsTrue() throws Exception {
Member tempMem = new Member();
tempMem.setMemberFirstName("Swagrid");
tempMem.setMemberLastName("McLovin");
tempMem.setMemberID("SM666");
SQLDUMMY.saveMember(tempMem); //Save member to dummy DB.
Member checkMem = new Member();
ArrayList<Member> memArr = SQLDUMMY.getAllMembers();
for (Member m : memArr) { // Look through all saved members
if (m.equals(tempMem)) { // If match, save to checkMem
checkMem = m;
}
}
assertTrue(tempMem.equals(checkMem)); // Make sure they are really equal.
String newfirstname = "Darius";
String newlastname = "DunkMaster";
assertTrue(memhandling.changeMember(tempMem, newfirstname, newlastname));
}
And here is the actual method:
public boolean changeMember(Member mem, String n1, String n2) {
try {
ArrayList<Member> memArr = SQLDUMMY.getAllMembers();
for (Member m : memArr) {
if (m.equals(mem)) {
m.setMemberFirstName(n1);
m.setMemberLastName(n2);
m.setMemberID(ensureUniqueID(m, m.getMemberID())); //Just a method call to another method in the same class to ensure ID uniqueness.
return true;
}
else {
return false;
}
}
}
catch (Exception e) {
System.out.println("Error4.");
}
return false;
}
I'd like to mock the SQLDUMMY (Which I created just to see if my tests would pass at all, which they do.) The SQLDUMMY class looks like this:
public class SQLDUMMY {
private static ArrayList<Member> memberList = new ArrayList<>();
private static ArrayList<Ship> shipList = new ArrayList<>();
public static ArrayList<Member> getAllMembers() {
return memberList;
}
public static void saveMember(Member m) {
memberList.add(m);
}
public static void deleteMember(Member memIn) {
memberList.remove(memIn);
}
public static void saveShip(Ship newShip) {
shipList.add(newShip);
}
public static ArrayList<Ship> getAllShips() {
return shipList;
}
public static void deleteShip(Ship s) {
shipList.remove(s);
}
}
It basically just consists of getters and add/remove for the ArrayLists that act as a contemporary DB storage.
Summary: How can I mock the SQLDUMMY class (DAO), so it is no longer a dependency for the Unit tests?
You need to read on how Mockito works.
The basic idea is that it extends you class and and overrides all methods and allows you to return what ever you want it too.
Syntax is :
SQLDummy sqlDummy = Mockito.mock(SQLDummy.class);
Mockito.when(sqlDummy.getAllShips()).thenReturn(new ArrayList< Ship >())

How do I mock a method with void return type in JMockit?

I'm using TestNG and JMockit for testing. My code goes like this:
public boolean testMethod(String a, String b) {
//processing .....
mockClass.mockMethod(a);
//processing....
}
The mockMethod():
Class MockClass {
public void mockMethod(String a) {
//some operations to mock
}
}
I'm using MockUp according to this question: (How to mock public void method using jmockit?)
I'm still getting the NPE. What am I doing wrong? Also, is it because I'm using it like this?
#Test
public void test() {
new Expectations() {
{
//for statements preceding mockMethod()....
new MockUp<MockClass>(){
#Mock
public void mockMethod(String a) {
//do nothing
}
};
}
};
}
I've put it outside Expectations() & used NonStrictExpectations too. How do I fix this?
If the method to be mocked is not returning anything, you don't need to do anything special in expectations. You can define your class to be mocked using #Injectable or #Mocked annotations in usual way. Optionally you can add an expectation to verify the number of times the method is called. Also you can add verification step to capture the argument "a" and do assertions on that. Refer below code sample.
#Tested
private MyClassToBeTested myClassToBeTested;
#Injectable
private MockClass mockClass;
#Test
public void test() {
// Add required expectations
new Expectations() {{
...
..
}};
// Invoke the method to be tested with test values;
String expectedA = "testValueA";
String expectedB = "testValueB";
boolean result = myClassToBeTested.testMethod(expectedA, expectedB);
// Assert the return value of the method
Assert.assertTrue(result);
// Do the verifications and assertions
new Verifications() {{
String actualA;
mockClass.mockMethod(actualA = withCapture()); times = 1;
Assert.assertNotNull("Should not be null", actualA);
Assert.assertEquals(actualA, expectedA);
...
..
}};
}
For void method mocking You can make Expectations without any result as shown below :
#Tested
private MyClassToBeTested myClassToBeTested;
#Injectable
private MockClass mockClass;
#Test
public void test() {
new Expectations() {{
mockClass.mockMethod(anyString);
}};
String inputA = "testValueA";
String inputB = "testValueB";
boolean result = myClassToBeTested.testMethod(inputA, inputB);
assertEquals(true, result);
}

Switching from Mockito to JMockit

I used to rely on Mockito until today I have a final class with some static methods so I've to switched to JMockit. I knew nothing about it before so the question is: how can I apply the similar logic from Mockito to JMockit?
public final class ServiceData extends BaseData {
private List<Data> data;
public ServiceData(List<Data> data) {
this.data = data;
// something else
}
public static Container getContainer() {
return super.getContainer();
}
public Data getDataAt(Index index) {
return super.getContainer().get(index);
}
}
The test written in Mockito looks like:
#Test
public void test() {
ServiceData mockServiceData = mock(ServiceData.class);
Data mockData = mock(Data.class);
// only stubbing some of the methods
Container mockContainer = spy(Container.class);
doReturn(something).when(mockContainer.someMethod());
when(mockServiceData.getContainer()).thenReturn(mockContainer);
when(mockServiceData.getDataAt(any(Index.class)).thenReturn(mockData);
// some assertions
}
This won't work since Mockito cannot mock final classes nor static methods (getContainer)
So how can I write the same logic in JMockit? Thanks.
The following is the JMockit equivalent for the example test:
#Test
public void test(
#Mocked final ServiceData mockServiceData, #Mocked final Data mockData,
#Mocked final Container mockContainer)
{
// only stubbing some of the methods
new Expectations(mockContainer) {{
mockContainer.someMethod(); result = "something";
mockServiceData.getContainer(); result = mockContainer;
mockServiceData.getDataAt((Index) any); result = mockData;
}};
// some assertions
}
To mock static methods the syntax is the same, except that you would write ServiceData.getContainer(); result = mockContainer; instead.

Categories

Resources