I am trying to mock a method using Mockito and JUnit. For some reason it keeps saying that the embedded method is never being invoked, despite the test fulfilling the if statement.
Here is my method that I am testing:
public List<LifeProduct> prune(List<LifeProduct> products) {
for (LifeProduct product : products) {
int id = product.getProductAnalyticsIdentifier();
boolean deleteAnnuity = id > 10014;
boolean deleteLifeInsurance = product.getLifeInsurance()
.getHighLevelLifeInsuranceGroupName()
.equals("string");
if (deleteAnnuity) {
annuityService.deleteAnnuityById(id);
}
if (deleteLifeInsurance) {
lifeInsuranceService.deleteLifeInsuranceById(id);
}
}
return products;
}
and here is my test with the iterator setup:
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mockList.iterator()).thenReturn(mockIterator);
when(mockIterator.hasNext()).thenReturn(true, false);
when(mockIterator.next()).thenReturn(mockProduct);
}
#Test
public final void testPrune() throws Exception {
for (LifeProduct mockProduct : mockList) {
mockProduct.setProductAnalyticsIdentifier(99999999);
doNothing().when(annuityService).deleteAnnuityById(anyInt());
List<LifeProduct> response = lifeProductDelegate.prune(mockList);
assertNotNull(response);
verify(annuityService).deleteAnnuityById(anyInt());
}
}
Your test has two issues:
You're using the mockList and therefore use one of the two values for mockIterator.hasNext()
You say that when mockIterator.hasNext() is called, it should first return true and then false. The issue here is that your test method iterates over mockList and therefore needs to call mockIterator.hasNext() and then uses the first, the true, value. The tested method #prune() then also attempts to iterate the list, but will only get the second, the false, value, thus skipping the loop. You don't need the loop in your test method, so you can and should remove it.
You incorrectly setup mockProduct
The second issue is mockProduct.setProductAnalyticsIdentifier(99999999). mockProduct is a mock, so the methods don't do anything when not configured for example via when(mockProduct...).... So the value 99999999 is not stored anywhere and #getProductAnalyticsIdentifier() in the test returns 0, the default value. What you actually want to do is to configure the getter method, for example with:
when(mockProduct.getProductAnalyticsIdentifier()).thenReturn(999999);
Now the mockProduct will return that value when #prune() asks for the id and later compares it with 10014.
Related
I am writing junit test cases for my project but i am facing one problem
Here is a method that i am using in one of my java class (GraphNodes.java)
public static ArrayList<String> getCSList() {
System.out.println(CSList.size()); // Output : 3
return CSList; // returns 3 elements in list
}
Now here is my test class for Junit
#Test
public void checkCSListCount(){
int actual= GraphNodes.getCSList().size(); // My exceptation here is 3 but in console it shows 0
int excepted = 3;
assertEquals(excepted,actual);
}
My junit is failing by saying excepted<3> but actual<0>
Also i cannot change the static method to only public because it will affect some functionality of the code and since i am new to junit, i am not getting idea how to fix this.so can anyone help me out here
Thanks in Advance!!
You need to validate how you populate the object CSList() during runtime and do exactly the same when you are running the test.
One option is to have a #BeforeEach method in your test where it will set the values of what you need during the test.
#BeforeEach
public void setUp() {
GraphNodes.setCSList(Arrays.asList("A","B","C"));
}
#Test
public void checkCSListCount(){
int actual= GraphNodes.getCSList().size();
int excepted = 3;
assertEquals(excepted,actual);
}
I think you are trying to write an integration test. So you should call the method, that fills the list with your 3 elements, before checking the list size. If all the logic for that is in your main method you should extract it into its own method.
Edit:
Sorry, my example is not very proper, I changed it a little.
I'm not sure if the title shows my question properly.
For example, I have functions:
class Dependency {
// create an element with id and data, add it into a list and return the element
public Element addElement(int id, data d) throws SomeException;
// remove an element from the list and return it
public Element removeElement(int id) throws SomeException;
}
Then I can mock it like:
private Element mockElement(int id, data dt) {
Element e = mock(Element.class);
when(e.getId()).thenReturn(id);
when(e.getData()).thenReturn(dt);
return e;
}
private Dependency mockDependency() {
List l = new List();
Dependency dependency = mock(Dependency.class);
// should I "implement" the internal logic when mocking?
when(dependency.addElement(intCaptor.capture(), dataCapture.capture())).thenAnswer(a->{
int id = intCaptor.getValue();
data dt = dataCaptor.getValue();
if (id < 0) { throw someException; }
Element e = mockElement(id, dt);
l.add(e);
return e;
};
when(dependency.removeElement(intCaptor.capture())).thenAnswer(a->{
int id = intCaptor.getValue();
if (id < 0) { throw someException; }
Element e = l.findElementInListById(id);
if (e == null) { return null; }
l.remove(e);
return e;
};
return dependency;
}
...
#Test
public void test() {
...
Dependency dependencyMock = mockDependency();
MyClass c = new MyClass(dependencyMock);
// it calls dependency.addElement()
c.addElement(1, data)
// it calls dependency.removeElement()
assertEquals(1, c.removeElement(1).getId());
...
}
This does work, but I wonder if it is a good idea to do so. All the examples I can find online about Mockito are basically simple when().then() statements. Can anyone please give me some advice?
The idea of mocking is to test the functionality you have written, the mocks should be only given for the services that are used by the method being tested.
For example, when you test the method public Element addElement(int id, data d) throws SomeException; you should call the original implementation and then you should assert the response that you expect to get for the given input.
Suppose inside addElement method you are internally calling a service myService.processData then you should mock the call to the myService.processData only and the rest of the flow should be as it would have been had the method been called in real scenario.
You should read more on Unit tests, one link I found is here
EDIT
In the example you have given, I think what you have done is, you have put the code inside the original dependency.addElement method inside the mock object you are creating, if you do that you will have to change your test case every time you make a change in the code because once you make a code change in original method dependency.addElement the code in test class becomes out of sync with it and you no longer be testing the feature. Even with this code you are not actually testing the original feature since dependency.addElement is mocked.
The correct approach is to call the original method dependency.addElement with a known input and assert the answer.
I hope this explains it.
I have a simple Unit Test that is failing. Hopefully I can explain this in simple terms as I've been looking at it for hours and I see what the issue is, but I am not too familiar the underlying theory behind Mocks so I am a bit confused and cannot fix it. I will summarize the issue very quickly and then paste the code below.
Basically, in my test method called getAllValidModelsTest(), it uses a for loop to iterate thru enum values of object type DeviceModel. There are only 5: [EX3400_24P, EX4300_32F, EX4300_48MP, SRX_345, FAUX].
So inside the for loop, before the Assert statement (Junit), it makes a static method call to getDevice(deviceId) and it should from there return a Device object. The first line under the for loop in the getAllValidModelsTest() mocks the elementMock object to return the current model that is being iterated over in the DeviceModels[] array that was returned from the .values() call on the enums DeviceModel class.
So my issue is, when it jumps in the 2nd iteration in my for loop (counting from 1), the Assert fails , because the 0th element in the DeviceModel[] array is obviously EX4300_32F, but in the #Before setUp annotation it is being mocked to return EX3400_24P. But the weird thing is, under the for loop inside the getAllValidModelsTest() method, it is being overridden/mocked again to return to the current model that is being iterated through when .getModel is called on the elementMock object, so it should be returning the SAME value...
This is how the class SwitchDeviceFactoryTest.java is constructed (the class with the Unit Test):
#PowerMockIgnore({"javax.net.ssl.*"})
#RunWith(PowerMockRunner.class)
#PrepareForTest({DataGatewayFactory.class, SwitchConfig.class, RouterConfig.class})
public class SwitchDeviceFactoryTest {
String deviceId = "testdevice";
String ip = "1.1.1.1";
DataGateway dbMock = Mockito.mock(DataGateway.class);
SwitchConfig swConfigMock = PowerMockito.mock(SwitchConfig.class);
RouterConfig routerConfigMock = PowerMockito.mock(RouterConfig.class);
TransportDeviceSecretsInfo secrets = new TransportDeviceSecretsInfo();
TransportDeviceSecretsData secretsData = new TransportDeviceSecretsData("root","rootPw", "sshUser", "sshPass", "snmpAuthPass", "snmpPrivPass");
IElement elementMock = Mockito.mock(IElement.class);
ITransportDeviceSecretsCrud transportDeviceSecretsCrud = mock(ITransportDeviceSecretsCrud.class);
ISwitchConfigCrud switchConfigCrud = mock(ISwitchConfigCrud.class);
IRouterConfigCrud routerConfigCrud = mock(IRouterConfigCrud.class);
IElementCrud elementCrud = mock(IElementCrud.class);
This is my setUp method that runs before the test. The only variables that should be of importance are the elementMock object, specifically the one being mocked to return the EX3400_24P object:
#Before
public void setup() throws Exception {
secrets.setSecretsData(secretsData);
PowerMockito.mockStatic(DataGatewayFactory.class);
Mockito.when(DataGatewayFactory.getInstance()).thenReturn(dbMock);
Mockito.when(dbMock.getTransportDeviceSecretsCrud()).thenReturn(transportDeviceSecretsCrud);
Mockito.when(transportDeviceSecretsCrud.getServerSecretsInfo(anyString())).thenReturn(Optional.of(secrets));
Mockito.when(transportDeviceSecretsCrud.getReportedSecretsInfo(anyString())).thenReturn(Optional.of(secrets));
when(dbMock.getElementCrud()).thenReturn(elementCrud);
doReturn(Optional.of(elementMock)).when(elementCrud).getById(anyString());
Mockito.when(elementMock.getModel()).thenReturn(DeviceModel.EX3400_24P.getModel());
Mockito.when(elementMock.getType()).thenReturn(ElementType.SWITCH);
Mockito.when(dbMock.getSwitchConfigCrud()).thenReturn(switchConfigCrud);
Mockito.when(switchConfigCrud.get(anyString())).thenReturn(Optional.of(swConfigMock));
Mockito.when(swConfigMock.getIp()).thenReturn(ip);
Mockito.when(dbMock.getRouterConfigCrud()).thenReturn(routerConfigCrud);
Mockito.when(routerConfigCrud.get(anyString())).thenReturn(Optional.of(routerConfigMock));
Mockito.when(routerConfigMock.getIp()).thenReturn(ip);
And the test method:
#Test
public void getAllValidModelsTest() throws Exception {
for (DeviceModel model: DeviceModel.values()) {
when(elementMock.getModel()).thenReturn(model.getModel());
if (model == DeviceModel.SRX_345)
when(elementMock.getType()).thenReturn(ElementType.ROUTER);
else
when(elementMock.getType()).thenReturn(ElementType.SWITCH);
Device device = DeviceFactory.getDevice(deviceId);
assertEquals(model, device.getModel());
}
}
The thing that doesn't make sense, is I was refactoring code, and only changed 2 lines (the elementCrud and elementMock .doReturn and .when calls) and it works perfectly fine on the develop branch.
When I debug, I can see that on the 2nd iteration of the for loop, .getModel returns EX3400_24P object inside the static getDevice method, when it should be returning model.getModel() , which would be the 2nd object being iterated on in the .values() enum array of DeviceModels... so it should be EX4300_32F.
On the develop branch, this works perfectly.... It's as if the Mockito mock object forgets what it's suppose to do when it jumps inside the DeviceFactory class inside the getDevice method once its called in my getAllValidModelsTest() method (i.e. Device device = DeviceFactory.getDevice(deviceId);)
Here is the .getDevice method from the DeviceFactory class:
public static Device getDevice(String serialNumber) throws Exception {
IElement element = dataGateway.getElementCrud().getById(serialNumber).get();
DeviceModel model = DeviceModel.valueOfLabel(element.getModel()); // right here is where it returns the wrong model... it returns EX3400_24P on the 2nd iteration
log.info("Found device {} in database", serialNumber);
if (serialNumber.startsWith(FakeDevicePrefix.ATGTEST.toString()) || serialNumber.startsWith(FakeDevicePrefix.FAKE.toString())) {
log.info("Detected FAKE/ATG serial number. Using FAUX device.");
model = DeviceModel.FAUX;
}
switch (element.getType()) {
case SWITCH:
SwitchConfig config = dataGateway.getSwitchConfigCrud().get(serialNumber).get();
return getDevice(serialNumber, config.getIp(), model);
case ROUTER:
RouterConfig rconfig = dataGateway.getRouterConfigCrud().get(serialNumber).get();
return getDevice(serialNumber, rconfig.getIp(), DeviceModel.SRX_345);
case PTP:
default:
log.warn("Unsupported device type {}", element.getType().toString());
throw new Exception("Unsupported device type " + element.getType().toString());
}
}
I did indeed comment out/remove the piece of code that mocks it to return EX3400_24P in the setUp() method with #Before annotation , but the tests fails with a NULL POINTER EXCEPTION at this point.
How does the .getModel method know to return what I mocked it to return in the previous class (SwitchDeviceFactoryTest.java) before it jumps into the DeviceFactory.java class? How does it remember that if I'm not passing it in as a variable into the getDevice() method?
Do I need to use PowerMock or something because this is a static method? How does this change anything?
Please help!
I have a void method and I want to test it. How do I do that?
Here's the method:
public void updateCustomerTagCount() {
List<String> fileList = ImportTagJob.fetchData();
try {
for (String tag : fileList) {
Long tagNo = Long.parseLong(tag);
Customer customer = DatabaseInterface.getCustomer(tagNo);
customer.incrementNoOfTimesRecycled();
DatabaseInterface.UpdateCustomer(customer);
}
} catch(IllegalArgumentException ex) {
ex.printStackTrace();
}
}
when the method returns void, you can't test the method output. Instead, you must test what are the expected consequences of that method. For example:
public class Echo {
String x;
public static void main(String[] args){
testVoidMethod();
}
private static void testVoidMethod() {
Echo e = new Echo();
//x == null
e.voidMethod("xyz");
System.out.println("xyz".equals(e.x)); //true expected
}
private void voidMethod(String s) {
x = s;
}
}
It might not be always true, but basic concept of unit test is to check if function works as expected and properly handling errors when unexpected parameters/situation is given.
So basically unit test is against the functions that takes input parameters and return some output so we can write those unit test.
The code like yours, however, includes some other dependency (database call) and that's something you can't execute unless you write integration-test code or real database connection related one and actually that's not recommended for unit test.
So what you need to do might be introducing unit test framework, especially Mockto/Powermock or some other stuff that provides object mocking feature. With those test framework, you can simulate database operation or other function call that is going to be happening outside of your test unit code.
Also, about how do I test void function, there is nothing you can with Assert feature to compare output since it returns nothing as you mentioned.
But still, there is a way for unit test.
Just call updateCustomerTagCount() to make sure function works. Even with just calling the function, those unit test can raise your unit test coverage.
Of course for your case, you need to mock
ImportTagJob.fetchData();
and
DatabaseInterface.getCustomer(tagNo);
and have to.
Let mocked
ImportTagJob.fetchData();
throw empty list as well as non-empty list and check if your code works as you expected. Add exception handling if necessary. In your code, there are two condition depends on whether fieList are null or non-null, you need to test it.
Also, mock those objects and let them throw IllegalArgumentException where you expect it to be thrown, and write an unit test if the function throws a exception. In Junit, it should be like
#Test(expected = IllegalArgumentException.class)
public void updateCustomerTagCountTest(){
// mock the objects
xxxxx.updateCustomerTagCount();
}
That way, you can ensure that function will throw exception properly when it has to.
I am using a series of Strict Mocks generated with EasyMock 3.2 to test a method that call's itself recursively. By setting the expectations of my mocks I can control the method so that it only calls itself once and then exits. However, I am seeing some very strange behaviour from EasyMock which looks like a bug, where it get's confused about the number of times a method is expected.
For example:
final Collection srcCollection = EasyMock.createStrictMock(Collection.class);
final NativeBroker broker = EasyMock.createMockBuilder(NativeBroker.class)
.addMockedMethod("getCollection")
.addMockedMethod("getSubject")
.createStrictMock();
expect(srcCollection.getURI()).andReturn(src);
replay(srcCollection, broker);
//run the test
broker.checkPermissionsForCopy(srcCollection, dest, newName);
verify(srcCollection, broker);
Leads to the error from EasyMock:
java.lang.AssertionError:
Expectation failure on verify:
Collection.getURI(): expected: 2, actual: 1
at org.easymock.internal.MocksControl.verify(MocksControl.java:226)
at org.easymock.EasyMock.verify(EasyMock.java:2080)
I have only instructed EasyMock to expect one result, so why does it think I want two? I also get the same error if I change my expectation to this:
expect(srcCollection.getURI()).andReturn(src).once();
...And it get's stranger...
If I change my expectation to this:
expect(srcCollection.getURI()).andReturn(src).times(2);
I get the error:
java.lang.AssertionError:
Expectation failure on verify:
Collection.getURI(): expected: 3, actual: 1
at org.easymock.internal.MocksControl.verify(MocksControl.java:226)
at org.easymock.EasyMock.verify(EasyMock.java:2080)
And, further if I change my expectation to this:
expect(srcCollection.getURI()).andReturn(src).anyTimes();
I get an even stranger error:
java.lang.IllegalStateException: last method called on mock already has a non-fixed count set.
at org.easymock.internal.MocksControl.replay(MocksControl.java:216)
at org.easymock.EasyMock.replay(EasyMock.java:2012)
Does anyone have any suggestions, or know of any limitations with EasyMock in recursive functions?
In my case I repeated same expected values 2 times. And it throws:
java.lang.IllegalStateException: last method called on mock already has a non-fixed count set.
E.G.
SchedulingDataForVersion dataForVersion = createNiceMock(SchedulingDataForVersion.class);
TaskSource mockedTaskSource = createNiceMock(TaskSource.class);
expect(mockedTaskSource.getOrderElement()).andReturn(orderLine).anyTimes();
expect(mockedTaskSource.getOrderElement()).andReturn(orderLine).anyTimes();
replay(dataForVersion, mockedTaskSource);
Correct one is:
SchedulingDataForVersion dataForVersion = createNiceMock(SchedulingDataForVersion.class);
TaskSource mockedTaskSource = createNiceMock(TaskSource.class);
expect(dataForVersion.getOrderElement()).andReturn(orderLine).anyTimes();
expect(mockedTaskSource.getOrderElement()).andReturn(orderLine).anyTimes();
replay(dataForVersion, mockedTaskSource
The error occurs when you add .anyTimes() and then you write the same call.
expect(mock.get()).andReturn("string").anyTimes(); --> first call with multiple support
expect(mock.get()).andReturn("string"); --> second call not needed
The solution is to write only the first call with multiple support
expect(mock.get()).andReturn("string").anyTimes();
I can't see anything wrong with this code.
Are the two mocked methods on the broker expected not to be called?
I made a test case. Can you make it fail?
public class AppTest {
public static interface Collection {
String getURI();
}
public static class NativeBroker {
public void checkPermissionsForCopy(Collection srcCollection, String dest,
String newName) {
srcCollection.getURI();
}
public Collection getCollection() {
return null;
}
public String getSubject() {
return null;
}
}
String src = "http://src.com";
String dest = "http://dest.com";
String newName = "my name";
#Test
public void testApp() {
final Collection srcCollection = EasyMock.createStrictMock(Collection.class);
final NativeBroker broker = EasyMock.createMockBuilder(NativeBroker.class)
.addMockedMethod("getCollection")
.addMockedMethod("getSubject")
.createStrictMock();
expect(srcCollection.getURI()).andReturn(src);
replay(srcCollection, broker);
// run the test
broker.checkPermissionsForCopy(srcCollection, dest, newName);
verify(srcCollection, broker);
}}