Mock method drawn to interface for searching null - java

I have an method which i must drawn to interface and write test for searching nullPointerExc. Here is the method:
boolean hasDocsChangedRequired (GroupProvider currentGroupAdm, GroupProvider groupAdm) {
return !currentGroupAdm.getDocs().equals(groupAdm.getDocs());
}
Somewhere in getDocs method is null.
I created the interface Changer with method:
boolean hasDocsChangedRequired();
And I implement this to class with the same body method as previously with SOLID rules
I have question how to good write test using mockito to fully cover this boolean function?

#pawel you can write test for checking your function like this, i am assuming that function is not static.
If you want to make it static , then you simply have to remove these 2 lines
#InjectMocks
ChangerImpl changer;
And in place of "changer" you have call corresponding Implemented class.
Hope this helps.
#RunWith(MockitoJUnitRunner.class)
public class TestSampleTest {
#InjectMocks
ChangerImpl changer;
#Test(expected = NullPointerException.class)
public void test1(){
GroupProvider currentGroupAdm = mock(GroupProvider.class);
doReturn(null).when(currentGroupAdm).getDocs();
GroupProvider groupAdm = mock(GroupProvider.class);
oReturn("sample2").when(groupAdm).getDocs();
changer.hasDocsChangedRequired(currentGroupAdm, groupAdm);
}
#Test
public void test2(){
GroupProvider currentGroupAdm = mock(GroupProvider.class);
doReturn("sample1").when(currentGroupAdm).getDocs();
GroupProvider groupAdm = mock(GroupProvider.class);
doReturn("sample2").when(groupAdm).getDocs();
Assert.assertThat(changer.hasDocsChangedRequired(currentGroupAdm, groupAdm), is(true));
}
#Test
public void test3(){
GroupProvider currentGroupAdm = mock(GroupProvider.class);
doReturn("sample1").when(currentGroupAdm).getDocs();
GroupProvider groupAdm = mock(GroupProvider.class);
doReturn("sample1").when(groupAdm).getDocs();
Assert.assertThat(changer.hasDocsChangedRequired(currentGroupAdm, groupAdm), is(false));
}
}

The output of your method
boolean hasDocsChangedRequired (GroupProvider currentGroupAdm, GroupProvider groupAdm) {
return !currentGroupAdm.getDocs().equals(groupAdm.getDocs());
}
solely depends on your two input objects.
In other words: you only have to provide input objects that give what you want to give for a specific test. Meaning: you probably want to write a test where currentGroupAdm.getDocs() gives something that is equal to groupAdm.getDocs(), and one where the two calls give a non-equal result.
Ideally, you don't need to mock anything here.

Related

Why values ​are overwritten when stubbing in Junit5?

I'm using Junit5 for test my spring code.
In the test code, I mock SetRepository, to make the getSize() method return value 40. Then I stubbed ListService's findSetSize() method and made it return value 30.
Then print the getSize() method value. Expected 40, but 30 printed.
It looks likegetSize() was overwritten while stubbing, but I'd like to know why.
// ListService.java
#Service
#RequiredArgsConstructor
public class ListService {
private final SetRepository setRepository;
public int findSetSize() {
int size = setRepository.getSize();
System.out.println(size); // first result: 40, second result: 30
return size;
}
public void saveToSet(int num) {
setRepository.saveNum(num);
}
}
// SetRepository.java
#Component
public class SetRepository {
Set<Integer> set = new HashSet<>();
public int getSize() {
return set.size();
}
public void saveNum(int num) {
set.add(num);
}
}
// Test code for ListService
#ExtendWith(MockitoExtension.class)
public class ListServiceWithMockTest {
#InjectMocks
#Spy
ListService subject;
#Mock
SetRepository setRepository;
#Test
#DisplayName("can get Set size")
public void findSetSizeTest() {
//given
when(setRepository.getSize()).thenReturn(40);
when(subject.findSetSize()).thenReturn(30);
//when
subject.saveToSet(100);
//then
System.out.println(setRepository.getSize()); // expected:40, result: 30
assertEquals(30, subject.findSetSize());
}
}
Here is my code. I know I shouldn't do stubbing like this, but I'm curious why the value comes out like this.
Thank U!!
In your example, you want to mock a method within the same class. But this is not possible in the way you did. You create a real object using #InjectMocks. You need to use Mockito.spy() to partially mock this.
If you want to get the results you expect correctly and really mock your findSetSize() method, you should change your test method to follow:
#Test
#DisplayName("can get Set size")
void findSetSizeTest() {
//given
ListService spyService = spy(subject);
when(setRepository.getSize()).thenReturn(40);
doReturn(30).when(spyService).findSetSize();
//when
subject.saveToSet(100);
//then
System.out.println(setRepository.getSize()); // expected:40, result: 30
Assertions.assertEquals(30, spyService.findSetSize());
}
Here you have to understand that mocking would work only when you call it on the instance of spy object. It's wrapped by a Mockito proxy which catches your call, and if you have overriden some method, it will call your new implementation instead of the original one.
Also the documentation related to spy says:
You can create spies of real objects. When you use the spy then the real methods are called (unless a method was stubbed).
You can review the answers here and here regarding the differences between when().thenReturn() and doReturn().when().

Java MockedStatic method is still called

So I'm using MockedStatic<> to mock a static method but it seems like the item inside is still getting called? If this is the case, what's the point of mocking it? I have the following setup:
Object being tested:
public class ObjectBeingTested {
public void methodBeingTested() {
Object obj = ObjectInQuestion.getInstance(new Object(), "abc");
// do stuff with obj
}
}
The object with static method:
public class ObjectInQuestion {
public static ObjectInQuestion getInstance(Object obj, String blah) {
someLocalVar = new FileRequiredObject();
// we get NullPointerException here cuz in test env, no files found
}
private ObjectInQuestion() {
// private constructor to make people use getInstance
}
}
Test code:
public class MyTestClass {
MockedStatic<SomeClass> mySomeClass;
#Mock ObjectInQuestion mMockedObjectInQuestion;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mySomeClass = mockStatic(SomeClass.class);
when(SomeClass.getInstance(any(), anyString()).thenReturn(mMockedObjectInQuestion);
}
#After
public void tearDown() {
mySomeClass.close();
}
}
My questions are the following:
Why calling ObjectInQuestion.getInstance() in the test class, it's totally fine but when it's being called from ObjectBeingTested, it runs the real construction?
I tried to use mockConstruction on FileRequiredObject, it still actually construct the object ... why?
You're using the wrong syntax for stubbing the static method. You want something like
mySomeClass.when(
()->SomeClass.getInstance(any(), anyString()))
.thenReturn(mMockedObjectInQuestion);
More information available here
Assuming MockedStatic<SomeClass> mySomeClass; is actually MockedStatic<ObjectInQuestion> mySomeClass;, I would try to simplify the setup using a classic try block.
In any case, sharing the actual test method might be able to shine some light. ;)

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);
}
}

MockedObject and Real Object give different results

I have started learning JUNIT.
Here is what i am trying to achieve.
I have a class which checks if the inputString is part of secretKey;
public class StringChecker {
public boolean isEqual(String name)
{
boolean isEqual = false;
if(getSecretKey().contains(name))
{
isEqual = true;
}
return isEqual;
}
public String getSecretKey()
{
return "OSKAR";
}
}
My test class is this
public class RandomCheck {
#Test
public void isEqualTest()
{
StringChecker stringChecker = mock(StringChecker.class);
when(stringChecker.getSecretKey()).thenReturn("james");
//assertEquals(true, new StringChecker().isEqual("OSKAR")); <----this test case passes
assertEquals(true, stringChecker.isEqual("james"));
}
}
When i use Mocked object it does not give me the expected result, hence failing the test. But when i use a real object it gives me expected result and passes the test.
Am i missing anything? Like any annotation
A mockito mock is an object having the interface of the mocked class, but not its implementation. Your StringChecker is mocked, meaning there is no implementation code making calls from isEqual to getSecretKey as you assume.
You could use mockito spy, See this SO question:
Mockito.spy() is a recommended way of creating partial mocks. The reason is it guarantees real methods are called against correctly constructed object because you're responsible for constructing the object passed to spy() method.
ROOKIE MISTAKE
Here's the rookie mistake i did (mentioned by Arnold).
I mocked the StringChecker class but i did not provide any implementation for isEqual(String) method.
And because there was no implementation, i was getting the default value. In this case false (return type of method is boolean).
Solution
Using static method spy(). (Again mentioned by #Arnold).
So here is what my working code looks like.
#Test
public void isEqualTest()
{
StringChecker stringChecker = new StringChecker();
StringChecker spy = spy(stringChecker);
when(spy.getSecretKey()).thenReturn("james"); // providing implementation for the method
assertEquals(true, spy.isEqual("james"));
}
What i learnt from it.
Just by mocking an object does not get your things done if you intend to use methods of mocked object (In simple terms PROVIDE IMPLEMENTATION for methods of mocked objects).
TIP
If you want to see the default value returned by mocked object, just call the method of mocked object in sysout(without giving implementation).
Hope it will help someone like me.Peace
An alternative way without mocking and with additional test cases:
#Test
public void isEqualTest() {
StringChecker stringChecker = new StringChecker() {
#Override
public String getSecretKey() {
return "james";
}
};
assertTrue(stringChacker.isEqual("james"));
assertTrue(stringChacker.isEqual("jam"));
assertTrue(stringChacker.isEqual("mes"));
assertFalse(stringChacker.isEqual("oops"));
}
BTW, the isEqual() can be simplified to one line:
public boolean isEqual(String name) {
return getSecretKey().contains(name);
}

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