I have a problem with JUnit test for my method
#Transactional
#Override
public void deleteOffer(Offer offer) {
List<String> offerPictures = this.getOfferPictures(offer);
if (offerPictures != null) {
System.out.println(offerPictures.size());
for (String stringName : offerPictures) {
this.deleteSinglePhoto(new File(hardDiscAddress + stringName));
this.deleteSinglePhoto(new File(hardDiscAddress + "sm_" + stringName));
}
}
offerDAO.delete(offer.getId());
}
I already have test for empty offerPcitures list, but now I need to write one for NOT empty list. Problem is I don't know how to mock getOfferPictures method to return not empty string list
#Override
public List<String> getOfferPictures(Offer offer) {
File dir = new File(hardDiscAddress);
List<String> resultantlist = new ArrayList<String>();
if (dir.isDirectory()) {
for (final File f : dir.listFiles()) {
if (f.getName().startsWith(offer.getPhotography())) {
resultantlist.add(f.getName());
}
}
}
return resultantlist;
}
And this is the test for empty list
#Test
public void testDeleteOffer() {
// given
testOfferServiceImpl = new OfferServiceImpl();
testOfferServiceImpl.hardDiscAddress = "C:/";
testOfferServiceImpl.offerDAO = offerDAOMock;
when(offerMock.getId()).thenReturn(1);
when(offerMock.getPhotography()).thenReturn("stringForTest");
doNothing().when(offerDAOMock).delete(1);
// when
testOfferServiceImpl.deleteOffer(offerMock);
// then
Mockito.verify(offerDAOMock, times(1)).delete(1);
}
You could use Mockito.spy to partially mock the instance you're testing, and return a non empty list:
#Test
public void testNotEmptyOffer() {
// Given
testOfferServiceImpl = new OfferServiceImpl();
testOfferServiceImpl.hardDiscAddress = "C:/";
testOfferServiceImpl.offerDAO = offerDAOMock;
// Spy (partially mock) the object
testOfferServiceImpl = Mockito.spy(testOfferServiceImpl);
doReturn(Arrays.asList("one", "two", "three")).
when(testOfferServiceImpl).getOfferPictures(offerMock)
// Test your logic here
}
Use something like Mockito. You can do:
Candidate candidate = mock(Candidate.class);
when(candidate.getFirstName()).thenReturn("Bob");
this is an example from project, works well. You will also have to annotate your test class with:
#RunWith(MockitoJUnitRunner.class)
you can then make the method return whatever you like. Hope that helps :)
Related
I am writing a simple test case but getting a null pointer exception in the return value.
Although when I debug the actual mocking is working , and my main code is also being triggered
My Test Case
#Test
public void testEmptyRequests() {
List<MyPojo> list = new ArrayList();
String env = "env-stub";
when(myService.fetchRecords(env)).thenReturn(list);
Assert.assertEquals(Integer.valueOf(0), myController.process(env, 1));
}
My Method
#Async
public Integer process(String environment, Integer id) {
List<MyPojo> list = myService.fetchRecords(environment);
if (list == null || list .isEmpty()) {
log.info("[0] claims to process");
return 0;
}
// Other logic here, Not relevant to this test case
}
change your test method to this:
#Test
public void testEmptyRequests() {
List<MyPojo> list = new ArrayList();
String env = "env-stub";
when(myService.fetchRecords(Mockito.anyString())).thenReturn(list);
Assert.assertEquals(Integer.valueOf(0), myController.process(env, 1));
}
You should mock the method you are using inside your code.
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!
When creating a test below
#Test
public void myTest() {
MyRepo myRepo = Mockito.mock(MyRepo.class);
when(myRepo.getMyItemList()).thenReturn(createMyItemList(3));
// More Test verification
}
private List<MyItem> createMyItemList(int count) {
List<MyItem> myItemList = new ArrayList<>();
while (count > 0) {
myItemList.add(createMyItem());
count--;
}
return myItemList;
}
private MyItem createMyItem() {
MyItemDetail myItemDetail = new MyItemDetail();
ItemDetailGen itemDetailGen = Mockito.mock(ItemDetailGen.class);
when(itemDetailGen.getItem()).thenReturn(myItemDetail);
return new MyItem(itemDetailGen);
}
I got error on the line of when(itemDetailGen... when running it
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at ...
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
If I debug into it, the crash happens on when(myRepo.getMyItemList... instead.
Why is this problem?
It seems like a return of a mock function (i.e. createMyItemList), shouldn't contain another mock within. My temporary fix is remove the private function mock, by creating a new constructor for MyItem to directly accept MyItemDetail object as below, which is not ideal, since the actual code doesn't use that.
private MyItem createMyItem() {
MyItemDetail myItemDetail = new MyItemDetail();
return new MyItem(myItemDetail);
}
UPDATED
Just to make it clearer, I'm showing all the class (simplified) content.
class MyRepo {
List<MyItem> myItemsList;
List<MyItem> getMyItemList() {
return myItemsList;
}
void addMyItemList(List<MyItem> myItemsList) {
this.myItemsList = myItemsList;
}
}
class MyItem {
private MyItemDetail myItemDetail;
public MyItem(ItemDetailGen itemDetailGen) {
this.myItemDetail = itemDetailGen.getItem();
}
public MyItem(MyItemDetail myItemDetail) {
this.myItemDetail = myItemDetail;
}
}
class MyItemDetail {
}
class ItemDetailGen {
MyItemDetail getItem() {
return new MyItemDetail();
}
}
Combine the class code and the test code, the entire test could be run to demonstrate the issue clearly.
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 >())
Unit under test as following:
#Component(value = "UnitUnderTest")
public class UnitUnderTest {
#Resource(name = "propertiesManager")
private PropertiesManager prop;
public List<String> retrieveItems() {
List<String> list = new ArrayList<String>();
String basehome = prop.get("FileBase");
if (StringUtils.isBlank(basehome)) {
throw new NullPointerException("basehome must not be null or empty.");
}
File target = new File(basehome, "target");
String targetAbsPath = target.getAbsolutePath();
File[] files = FileUtils.FolderFinder(targetAbsPath, "test");//A utility that search all the directories under targetAbsPath, and the directory name mush match a prefix "test"
for (File file : files) {
list.add(file.getName());
}
return list;
}
}
Test case as below:
public class TestExample {
#Tested
UnitUnderTest unit;
#Injectable
PropertiesManager prop;
/**
*
*
*/
#Test
public void retrieveItems_test(#NonStrict final File target,#Mocked FileUtils util){
new Expectations(){
{
prop.get("FileBase");
result="home";
target.getAbsolutePath();
result="absolute";
FileUtils.FolderFinder("absolute", "test");
result=new File[]{new File("file1")};
}
};
List<String> retrieveItems = logic.retrieveItems();
assertSame(1, retrieveItems.size());
}
}
It's failed. The actual ressult of retrieveItems is empty. I found that "FileUtils.FolderFinder(targetAbsPath, "test")" is always return an empty File[]. That's really weird.
It probably because i mocked File instance "target" as well. It works fine if i only mocking the static method FileUtils.FolderFinder.
Does anyone know what the problem is? And is it possible to mock a local variable instance like i required here? Such as this target instance?
Thanks a lot!
The problem is that i should define which method i want to mock.
#Test
public void retrieveItems_test(#Mocked(methods={"getAbsolutePath"}) final File target,#Mocked FileUtils util){
new Expectations(){
{
prop.get("FileBase");
result="home";
target.getAbsolutePath();
result="absolute";
FileUtils.FolderFinder("absolute", "test");
result=new File[]{new File("file1")};
}
};
List<String> retrieveItems = logic.retrieveItems();
assertSame(1, retrieveItems.size());
}
This will be fine.