How to verify method is only ever called with expected arguments? - java

I'd like to verify that calls against a mock only ever happen with some expected argument values, and never with anything else.
public interface ADependancy {
public void method(String parameter, String otherParameter);
}
public class Foo {
private ADependancy myHelper;
public Foo(ADependancy helper) {
this.myHelper = helper;
}
public void good() {
myHelper.method("expected","expected");
myHelper.method("expected","expected");
myHelper.method("expected","expected");
}
public void bad() {
myHelper.method("expected","expected");
myHelper.method("expected","UNexpected");
myHelper.method("expected","expected");
}
}
I tried this:
public class FooTest extends TestCase {
private ADependancy mock =mock(ADependancy.class);;
private Foo foo = new Foo(mock);
#Test
public void testGood() {
foo.good();
validateOnlyCalledWithExpected();
}
#Test
public void testBad() {
foo.bad();
validateOnlyCalledWithExpected();
}
private void validateOnlyCalledWithExpected() {
verify(mock,atLeastOnce()).method(eq("expected"),eq("expected"));
verify(mock,never()).method(not(eq("expected")),not(eq("expected")));
}
}
Expecting testBad to fail, but instead the test passes. If method only takes one parameter, this works as expected.

It was a logic mistake.
I wanted to assert that each argument is never anything but the expected value.
But instead, what I was actually asserting was that it never happens that they are ALL not the expected value.
So with the way I had it, it did not fail as desired, because in fact, some of the arguments are not not the expected value, therefore the method is never called with all the parameters not the expected value, and the verify passes.
Thus, this works for what I wanted:
private void validateOnlyCalledWithExpected() {
verify(mock,atLeastOnce()).method(eq("expected"),eq("expected"));
verify(mock,never()).method(not(eq("expected")),anyString());
verify(mock,never()).method(anyString(),not(eq("expected")));
}

You could use the verifyNoMoreInteractions static method, documented at http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#finding_redundant_invocations.
verify(mock).method(eq("expected"),eq("expected"));
verifyNoMoreInteractions(mock);
Alternatively, you could write
verify(mock).method(eq("expected"),eq("expected"));
verify(mock,never()).method(anyString(),anyString());
because the second call to verify will disregard the calls that have already been verified.

Related

Check that static void method was called, with Mockito

There are considerable answers around, that seem to address this topic, but somehow it is never working out for me. I must be making some mistake, somewhere.
I have this class.
public class myClass {
public static void myEdit(boolean flag) throws Exception {
if (flag) {
System.out.println("Wow!");
} else {
PortalBL.mySave(flag);
}
}
public static void mySave(boolean wtv) throws Exception {
System.out.println("Doesn't matter");
}
}
I want to write a simple unit test, where I call myEdit, with flag = false. I just want the test to pass if it confirms that the PortaBL.mySave was called. I don't want it to be executed, I just want to verify if it was called.
I am trying to do it like this:
#Test
public void myTest() throws Exception {
try (MockedStatic<PortalBL> mock = Mockito.mockStatic(PortalBL.class)) {
mock.when(() -> PortalBL.mySave(anyBoolean())).thenAnswer((Answer<Void>) invocation -> null);
PortalBL.myEdit(false);
mock.verify(() -> PortalBL.mySave(anyBoolean()));
}
}
The idea would be to mock the static method, so that I can handle it without executing it and later verify that it was called, when I call PortalBL.myEdit
I believe that the class is badly written. It shouldn't be static method, I should be instantiating this class as an object and carry on. But, let's say that we are determined to test this particular scenario, as it is. Is it possible?
Btw, when I execute the PortaBL.myEdit(false) line, it isn't truly executed. I believe it is because the machine is thinking it is a mock, and doesn't know what to do with it when it is called..

How do I test a void method sets the correct value for a private variable

public class ClassOne {
private String exampleString;
public String getExampleString(){
return this.exampleString;
}
public void setExampleString(String exampleString){
this.exampleString;
}
}
public class ClassOneTest {
ClassOne classOne = new ClassOne();
#Test
void getExampleStringTest(){
classOne.setExampleString("test");
assertEquals("test", classOne.getExampleString());
}
#Test
void setExampleStringTest(){
ClassOne classOneMock = mock(ClassOneMock.class);
ClassOneMock.setExampleString("test");
verify(classOneMock, times(1));
}
I have two methods, one which sets a variable and another which gets the value of that variable. I want to be able to test by mocking the set method and verifying that the value of the variable set is correct.
I tried using ArgumentCaptor, but I'm not sure if I understand it enough to use it.

Skip null check in mockito

I am trying to write unit test cases for one of the methods in code.Below is the method
public boolean isValid() {
if(object == null)
return false
//do something here and return value.
}
The object is created by this method which is done before without getter setter method.
private Object returnObject() {
object = Axis2ConfigurationContextFactory.getConfigurationContext();
return object;
}
When I try to test isValid(), the object is always null, so it never goes in the code to do something.
I was checking if there is any way to skip that line or make the object not null. I also tried creating an object using returnObject method. But it uses Axis library classes which throws error if it does not find certain data. What can be done in this case? I am dealing with legacy code so any pointers would be helpful.
Edit : Adding test implementation.
#PowerMockIgnore({ "javax.xml.*", "org.w3c.dom.*", "javax.management.*" })
public class ClassTest {
private ClassTest classTestObj;
#BeforeMethod
public void callClassConstructor() {
classTestObj = //call class constructor
}
#BeforeClass
public void setUpClass() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public boolean isValidTest() {
Boolean result = classTestObj.isValid();
Assert.assertEquals(result);
}
}
As I mentioned in the before comment, you can make use of MockedStatic to mock the static method - https://javadoc.io/static/org.mockito/mockito-core/4.4.0/org/mockito/Mockito.html#static_mocks
So your code will somewhat look like the below one if you are making use of Mockito instead of PowerMockito.
#RunWith(MockitoJUnitRunner.class)
public class ClassTest
{
#Mock
private Object mockAxis2ConfigurationContextFactoryObject;
#Test
public boolean isValidTest() {
try (MockedStatic<Axis2ConfigurationContextFactory> mockedStatic = mockStatic(Axis2ConfigurationContextFactory.class)) {
mockedStatic.when(()->Axis2ConfigurationContextFactory.getConfigurationContext()).thenReturn(mockAxis2ConfigurationContextFactoryObject);
Boolean result = classTestObj.isValid();
Assert.assertEquals(result);
}
}

Verify private static method on final class gets called using PowerMockito

I have the following class
public final class Foo {
private Foo() {}
public static void bar() {
if(baz("a", "b", new Object())) { }
}
private static boolean baz(Object... args) {
return true; // slightly abbreviated logic
}
}
And this is my Test:
#PrepareOnlyThisForTest(Foo.class)
#RunWith(PowerMockRunner.class)
public class FooTest {
#Test
public void bar() {
PowerMockito.mockStatic(Foo.class); // prepare
Foo.bar(); // execute
verifyPrivate(Foo.class, times(1)).invoke("baz", anyVararg()); // verify - fails
}
}
For that, I get the following error message - and I don't understand why...
Wanted but not invoked com.example.Foo.baz(
null );
However, there were other interactions with this mock.
Removing the prepare line above seems to make the verify line pass no matter for how many times you check for... :(
(Our SONAR code checks enforce that each test has some sort of assertXyz() in it (hence the call to verify()) and enforces a very high test coverage.)
Any ideas how to do this?
The problem with your code is that you mock Foo so your method implementations won't be called by default such that when you call Foo.call() it does nothing by default which means that it never avtually calls baz that is why you get this behavior. If you want to partially mock Foo, mock it using the option Mockito.CALLS_REAL_METHODS in order to make it call the real methods as you seem to expect, so the code should be:
#PrepareOnlyThisForTest(Foo.class)
#RunWith(PowerMockRunner.class)
public class FooTest {
#Test
public void bar() throws Exception {
PowerMockito.mockStatic(Foo.class, Mockito.CALLS_REAL_METHODS); // prepare
...
}
}

Mockito: using a method in "thenReturn" to return a mock doesn't work

I have encountered what I assume might be a bug with Mockito, but was wondering if anyone else can shed light as to why this test doesn't work.
Basically, I have two objects, like this:
public class FirstObject {
private SecondObject secondObject;
public SecondObject getSecondObject() { return secondObject; }
}
public class SecondObject {
private String name;
public String getName() { return name; }
}
The first object is mocked via annotation and the before method:
#Mock
FirstObject mockedFirstObject;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
The second object is mocked in a method:
public SecondObject setupMockedSecondObject() {
SecondObject secondObject = Mockito.mock(SecondObject.class);
Mockito.when(secondObject.getName()).thenReturn("MockObject");
return secondObject;
}
When thenReturn contains a direct call to this method to setup and obtain a mock of the second object, it fails:
#Test
public void notWorkingTest() {
Mockito.when(mockedFirstObject.getSecondObject()).thenReturn(setupMockedSecondObject());
Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}
But, when the mock returned by the same method is assigned to a local variable, which is used in thenReturn, it works:
#Test
public void workingTest() {
SecondObject mockedSecondObject = setupMockedSecondObject();
Mockito.when(mockedFirstObject.getSecondObject()).thenReturn(mockedSecondObject);
Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}
Are we doing something wrong or is this indeed a bug/limitation in Mockito? Is there a deliberate reason for this not working?
This is indeed a limitation of Mockito, and it is referenced in their FAQ:
Can I thenReturn() an inlined mock()?
Unfortunately you cannot do this:
when(m.foo()).thenReturn(mock(Foo.class));
// ^
The reason is that detecting unfinished stubbing wouldn't work if we allow above construct. We consider is as a 'trade off' of framework validation (see also previous FAQ entry). However you can slightly change the code to make it working:
//extract local variable and start smiling:
Foo foo = mock(Foo.class);
when(m.foo()).thenReturn(foo);
The workaround, as mentioned, is to store the desired returned value in a local variable, like you have done.
The way I understand it is that Mockito validates the usage you make of it every time you call its methods. When another method is called during an on-going stubbing process, you are breaking its validation process.
You can't use a method in thenReturn, but you can in thenAnswer
Your code will be called after the when condition will occur,
unlike any workaround based on thenReturn
Thus you could write:
#Test
public void nowWorkingTest() {
Mockito.when(mockedFirstObject.getSecondObject()).thenAnswer(new Answer<Map>() {
#Override
public Map answer(InvocationOnMock invocation) {
return setupMockedSecondObject();
}
});
Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}
Let find another example here
#Test
public void testAuthenticate_ValidCredentials() throws FailedToAuthenticateException {
String username = "User1";
String password = "Password";
/*Configure Returning True with when...thenReturn configuration on mock Object - Q5*/
//Write your code here
assertTrue(authenticator.authenticateUser(username, password));
}

Categories

Resources