I have some pretty simple code as shown below.
#Test
public void bugInInvokingASpyAndVerification() throws ColdDayException {
//given
Engine en = new Engine();
Engine spyEngine = spy(en);
Vehicle realDeal = new Vehicle(new Wheel(), spyEngine, new Brake());
Vehicle spyVehicle = spy(realDeal);
//When part - set-up stubs
when(spyVehicle.start(true)).thenReturn("Sure");
//Mockito.reset(spyVehicle);
//then part - actual calls + verifications
String x = spyVehicle.start(true);
assertEquals(x, "Sure");
verify(spyVehicle, times(1)).start(true);
verify(spyEngine, atLeastOnce()).startEngine(true);
verify(spyEngine, times(1)).startEngine(true);
}
The above code seems to record the 'when' call as the first call to the 'start' & hence the first 'verify' fails. The code works only when I uncomment the call to 'reset'. I am using Mockito 2.1.0 on Windows, with Java 1.8.
Indeed, in the line when(spyVehicle.start(true)).thenReturn("Sure"); you call start.
There are several ways to avoid this.
One of them is use doReturn:
doReturn("Sure").when(spyVehicle).start(eq(true));
Notice, that here we are are doing stubbing and not calling the method.
Related
I have this Method that throws an IllegalArgumentException when somebody tries to call it with value 0.
I want to write several stub and mock tests - for example - for the method getFrequentRenterPoints.
I coudn't figure out any "when" or "verify" statements which are used in mocks so I mixed parts of mocks and parts of stubs together and came up with this:
#Test
public void methodGetFrequentRenterPointsShouldThrowIllegalArgumentException() {
//given
Movie movieMock = mock(Movie.class);
//when
movieMock.getFrequentRenterPoints(0);
//then
assertThrows(IllegalArgumentException.class, () -> {
movieMock.getFrequentRenterPoints(0);
});
}
Is it okay to have in a class with other Mocks, or if I want to use assertThrows should I change this into a stub? Or can I use assertThrows with mocks?
The answer from Benjamin Eckardt is correct.
But I try to approach this question from another point of view: when to use mocking? This is one of my favourite answers to that question.
So in practise:
Say your code is like (just guessing all the business objects & names...):
List<RenterPoints> getFrequentRenterPoints(int renterId) {
if(p <= 0) {
throw new IllegalArgumentException();
}
// this is just the rest of code in which your test does not enter because
// of thrown exception
return somethingToReturn();
}
For this you do not need and you should not want to mock anything here.
But when things get more complicated like your method would be like:
List<RenterPoints> getFrequentRenterPoints(int renterId) {
if(p <= 0) {
throw new IllegalArgumentException();
}
// What is this?
// It is injected in the Movie - say - like
//
// #Resource
// private RenterPointService renterPointService;
List<RenterPoints> unfiltered = renterPointService.getRenterPoints(renterId);
return filterToFrequent(unfiltered);
}
Now if you test renterId >= 1 what about this renterPointService how do you instantiate it to not get NPE? Say if it is injected and requires to pull up heavy framework for testing or it requires very heavy construction or so? You do not, you mock it.
You are testing the class Movie not the class RenterPointService so you should not bother to think how RenterPointService works but what it returns when used in the class Movie. Still: you do not mock the class Movie which you are testing.
Assuming using you are using Mockito and using annotations the mocking would be then done in your test class like:
#Mock
private RenterPointService renterPointService;
#InjectMocks
private Movie movie;
Then you would do mocking of methods for renterPointService like:
when(renterPointService.getRenterPoints(anyInt))
.thenReturn(someListContaineingMockRenterPointsForThisTest);
Usually you expect the tested production method to throw and not the mock or stub. I drafted it by using new Movie().
Furthermore in that case it does not really make sense to separate the calls into when and then because if movieMock.getFrequentRenterPoints(0); throws, assertThrows(...) will never be executed.
To apply the given/when/then structure with the assertThrows API you could extract the passed lambda in some way, but I personally don't see much benefit in it.
#Test
public void methodGetFrequentRenterPointsShouldThrowIllegalArgumentException() {
// given
Movie movieMock = new Movie();
// when/then
assertThrows(IllegalArgumentException.class, () -> {
movieMock.getFrequentRenterPoints(0);
});
}
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'm making a test for a service with a mock.
The problem is to create and inject instance directly from the class to test.
The source is shown below.
public OrderOutDTO createOrder(OrderSessionDTO orderSessionDTO) {
Order order = orderRepository.save(new Order(orderSessionDTO));
CreateOrderResDTO callServiceOrder = callService.createOrder(new CreateOrderReqDTO(order));
CreateOrderReqDTO createOrderReqDTO = mock(CreateOrderReqDTO.class);
createTrace(order, callServiceOrder.getData().getReceipt().getTransactionHash(), Trace.PUBLIC);
return new OrderOutDTO(order, null);
}
and test source is shown below.
#Test
public void createOrder() {
// given
CallService callService = mock(CallService.class);
CreateOrderResDataDTO createOrderResDataDTO = mock(CreateOrderResDataDTO.class);
// when
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
OrderOutDTO order = orderService.createOrder(orderSessionDTO);
// then
assertThat(order, is(Matchers.notNullValue()));
assertThat(order.getOrder(), is(Matchers.notNullValue()));
assertThat(order.getOrder().getReceiver().getName(), is("test"));
}
I thought this test would finish well. But in the code below, it returned null and failed.
// callService.createOrder(new CreateOrderReqDTO(order)) return null
CreateOrderResDTO callServiceOrder = callService.createOrder(new CreateOrderReqDTO(order));
It doesn't seem to recognize it because the service injects a new instance. I want the mock data returned. What should I do?
In the following line you're mocking behavior on createOrderReqDTO as param:
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
whereas further, you're passing some other object:
OrderOutDTO order = orderService.createOrder(orderSessionDTO);
This behavior is not recognized, you would have to pass the same thing you mocked before.
I found it myself!
I use argumentMatchers.
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
to
when(callService.createOrder(any())).thenReturn(createOrderResDTO);
thank you.
So I'm tesing using Junit, quite new to it.
I am trying to test methods in a class called SetOfUsers as follows:
#Test
public void testFindUserByName() {
System.out.println("findUserByName");
String name = "";
SetOfUsers instance = new SetOfUsers();
User expResult = null;
User result = instance.findUserByName(name);
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
}
So I wanted to check the name of a user entered in Bob for instance in the name string like this
String name = "Bob";
since I have a user called Bob in the setOfUsers class.
The output window displays this message
Failed: expected:<null> but was:<Staff name:Bob, Staff pass:abc123>
What can I do to make this a pass?
Read about BDD, this is very nice technique for making tests easy to write and understand (read)
Test-driven development is a software development methodology which essentially states that for each unit of software, a software developer must:
define a test set for the unit first;
then implement the unit;
finally verify that the implementation of the unit makes the tests succeed.
Well written test should have GivenWhenThen sections
(Given) some context
(When) some action is carried out
(Then) a particular set of observable consequences should obtain
This style is known as SpecificationByExample
Given-When-Then is a style of representing tests - or as its advocates would say - specifying a system's behavior using SpecificationByExample.
Example test
#Test
public void testFindUserByName() {
// given
SetOfUsers instance = new SetOfUsers();
// when
User result = instance.findUserByName("Bob");
// then
assertEquals("Bob", result.getName());
}
Nice to read:
Arrange Act Assert Alternatives
Maintainable Tests
This test is always going to fail because the last line is
fail("The test case is a prototype.");
The reason your test is failing now is because of the line above,
assertEquals(expResult, result);
You are setting your expected result to null and the result you are getting from the name, "", is probably an empty String as well from that error message. You need to have expResult to be the same as what you expect instance.findUserByName("Bob") to return. However, unless you initialize the instance to be set with a User Object the objects will not match, so it might be better to either mock it to return a pre-created User object so they match, or create a User object with the same properties as the one you expect to be returned check the fields of the User Object returned and the User object you created to be sure they match.
If you want to check for what the user for Bob is, change the code to this:
#Test
public void testFindUserByName() {
System.out.println("findUserByName");
String name = "Bob";
SetOfUsers instance = new SetOfUsers();
User expResult = <Create an object you expect instance.findUserByName("Bob") to return>;
User result = instance.findUserByName(name);
//Check fields here.
assertEquals(expResult.getUserName(), result,getUserName());
// TODO review the generated test code and remove the default call to fail.
}
You can't test for null using assertEquals().
To test for null, use:
assertNull(result);
I don't understand the question, but if you want to search for "Bob" why you initialize name=""? The test should be:
#Test
public void testFindUserByName() {
//Create SetOfUsers
//Add new User with name Bob
//FindByUsername("Bob")
//AssertEqual(User.getName(), "Bob")
}
I know there are several question about void-method Unit-Testing, but my question is different.
I'm learning java, so my boss give me some tasks with different requirements on my tasks.
In my actual task, there is a requirement which says, the jUnit test must cover >60%. So I need to test a very simple method to reach this 60%. The method is the following:
public void updateGreen() {
// delete this outprint if the Power Manager works
System.out.println(onCommand + "-green");
// p = Runtime.getRuntime().exec(command + "-green");
// wait until the command is finished
// p.waitFor();
}
Because of intern problems, I can't execute the command with the Runtime task. So there is only a System.out in this method.
I've multiple methods like that, so tests for this method will cover over 10% of my whole code.
Is it useful to test such a method? When yes, how?
If there is a lot of such methods, the thing which you might want to test here is that updateScreen() uses the right string, "some-command-green" and that the System.out is being invoked. In order to do this you might want to extract System.out into an object field and mock it (i.e. with Mockito's spy()) to test the string that was provided to println.
I.e.
class MyClass{
PrintStream out = System.out;
public void updateGreen() { ... }
}
In test:
#Test
public void testUpdate(){
MyClass myClass = new MyClass();
myClass.out = Mockito.spy(new PrintStream(...));
// mock a call with an expected input
doNothing().when(myClass.out).println("expected command");
myClass.updateGreen();
// test that there was a call
Mockito.verify(myClass.out, Mockito.times(1)).println("expected command");
}
You could return true if the method ran successfully and false otherwise. It would be easy to test for this.
You could also test the output of this method, as described here:
Should we unit test console outputs?
But in my experience, it is much better to have methods return an optimistic or pessimistic value (true/false, 1/0/-1 etc) to indicate their status.
You can also write a getter method for the onCommand flag:
public string getFlag(){
// some logic here
return "green";
// otherwise default to no flags
return "";
}
You could test that onCommand + "-green" has been written to System.out by using the System Rules library.