I am writing JUnit test cases for my Service classes.
I have created dummy data to understand my scenario.
#Service
MainClass {
#Autowired
C c;
public void someServiceMethod(){
ResultClass someResult = c.getResult(string,string, int, int, List<String>,boolean);
}
}
#Service
public class C {
#Autowired
SomeRepository someRepository;
public ResultClass getResult(string,string, int, int, List<String>,boolean){
ABC returnSomeClassObject = someRepository.getSomeData(String,int,int);
}
}
#Test
MainClassTest {
#MockBean
SomeRepository someRepository;
when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(SomeRepository);
//calling MainClass method
MainClass.someServiceMethod();
}
Class C's getSomeData() method returning ABC class object which is NULL and latter setting into another same class type object.
After setting value I am getting NULLPointerException as ABC is NULL.
Anybody have any idea where I am going wrong?
You are not returning expected object while writing mock statement
#Service
public class C {
#Autowired
SomeRepository someRepository;
public ResultClass getResult(string,string, int, int, List<String>,boolean){
ABC returnSomeClassObject = someRepository.getSomeData(String,int,int);
//Your return type should be ResultClass
// Where your return statement
// What is ABC?
}
}
#Test
MainClassTest {
#MockBean
SomeRepository someRepository;
when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(SomeRepository);
// Why are you returning SomeRepository, This Should return object of ABC
#MockBean
ABC mockResultClass
when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(mockResultClass);
//calling MainClass method
MainClass.someServiceMethod();
}
You are calling MainClass.someServiceMethod() which in turn calls getResult of class C. You should be mocking class C and using when-thenReturn on getResult() of C class if your intention is to test someServiceMethod() of Main class. Autowired will not work here since this is a Unit test and hence the instance of C c in Main class will be null.
Something like below:
#MockBean
C c;
when(c.getResult(anyString(), anyString(),anyInt(),anyInt(), any(List.class), anyBoolean()).thenReturn(someResult);
c.getResult(string,string, int, int, List<String>,boolean);
So, first of all, we need to be clear on what exactly you are unit testing. If you are trying to unit test someServiceMethod inside of MainClass, then that means you should NOT be also testing the functionality of someRepository. The idea is that each unit test should only be testing just that, a unit of code. So, to do that we need to use stubs as stand-ins for what would actually happen when you call methods owned by other classes. Then, we would write a differrent unit test just for someRepository.getSomeData() to confirm that it is also working as intended. In this manner, when get an error later down the line we will know exactly where we are encountering an issue.
Another issue I see is there is an apparent mismatch of return types for getResult() in C. The method says it returns a ResultClass, but when you call getSomeData you are expecting an ABC object. Either you left out the details where you convert the object back to a ResultClass, or that is a mistake. I'm going to assume the former unless you say otherwise.
With that in mind, let's write our test. Here's how I would write the test:
#RunWith(SpringRunner.class)
public class MainClassTest {
#Mock
C c;
#InjectMocks
MainClass mainClass;
#Test
public void testSomeServiceMethod {
ResultClass resultClass = new ResultClass(); //relevant constructor details here, mockbean, etc. you get the idea
//set any desired data for resultClass here
Mockito.when(c.getResult(anyString(), anyString(),
anyInt(), anyInt(), any(List.class), anyBoolean()))
.thenReturn(resultClass);
ResultClass newResult = mainClass.someServiceMethod();
//relevant test assertions here
}
}
As you can see, we are creating a ResultClass in the test, and telling Mockito to return that when getResult is called instead of what you would normally expect it to return. While the functionality may seem limited now, this is preferred as we only testing the MainClass and not the rest of our method calls.
In addition to this, we can (and should) write tests for getResult in C, and getSomeData in SomeRepository. I will leave it to you to write those tests.
EDIT: accidentally posted a bit early, fixing now.
Related
Let's assume I have an object like this:
public ClassA() {
public void start() {
...
ClassB something = getSomeStuff();
...
}
protected ClassB getSomeStuff() {
return new ClassB(render, response);
}
}
Then I'm trying to do some unit-testing like this where I do a spy on a method-call on a spied object:
#Spy private ClassA classA;
#Mock private ClassC classC;
...
#Test
void test1() {
ClassB classB = spy(classA.getSomeStuff());
doReturn(classC).when(classB).getResults();
classA.start();
}
When I run this test and it comes down to this last line, I can see in my debugger that it is not returning classC.
Is this because it is not possible to do nested spying? Or is somehting wrong in my setup? Or should I approach this differently?
Details:
junit: 5.7.0
mockito: 3.12.4
When we look at the code presented, we see that calling classA.getSomeStuff() will return a new instance of ClassB with every call, i.e. classA.getSomeStuff() == classA.getSomeStuff() will evaluate to false.
What does that mean for our test setup? We construct a spy:
ClassB classB = spy(classA.getSomeStuff());
but this spy is never used. When we call classA.start(), it will call classA.getSomeStuff() again, and a new (non-spy) ClassB-instance is returned.
This is an example of code that is difficult to test: we have no easy way to control or verify the behaviour of the ClassB-instance used during the test. We normally avoid this problem by using the Inversion of Control principle (wikipedia.com). Whether this is applicable in this situation I cannot say. For this, I would have to see more of the code, and it would most probably be out of scope for StackOverflow.
As a quick and dirty fix, we can mock the call to classA.getSomeStuff() after we have created our mock:
#Spy private ClassA classA;
#Mock private ClassC classC;
...
#Test
void test1() {
ClassB classB = spy(classA.getSomeStuff());
when(classB.getResults()).thenReturn(classC);
when(classA.getSomeStuff()).thenReturn(classB);
classA.start();
}
As an aside: When using mockito, we should prefer the form
when(someMock.someMethod()).thenReturn(someResult);
over
doReturn(someResult).when(someMock).someMethod();
The former guarantees type safety at compile time, the latter does not. It is not always possible to use the former form (e.g. for methods returning void we have to use the latter form).
I have a test that is testing a Spring #Service class. This service class autowires in a dao #Repository. The dao also autowires in a class to provide extra functionality. I would like to mock the calls in the dao so I have something like so:
#DisplayName("Tests for ...")
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MyServiceTest
{
#Injectable
TheRepository myDao;
#Tested(fullyInitialized = true)
TheService myServiceUnderTest;
#Nested
#Tag("...")
#DisplayName("Tests for method: ...")
class TestClassContainer {
#Test
public void test1() {
IAnalysisDataScenario data = new CommonAnalysisDataScenario();
new Expectations() {{
myDao.nameExists(anyString); result = data.mockedNameExists();
...
}};
Map<String, Object> result = myServiceUnderTest.getAnalysis(data.getName(),data.getId());
assertTrue(!result.isEmpty());
}
}
}
The call to getAnalysis in the service calls the dao method nameExists which I want to return the result from mockedNameExists in the Expectations block but I can't figure out what I'm doing wrong.
This is what I see when I run the test:
Missing 1 invocation to:
...dao.impl.TheRepository#nameExists(any String)
on mock instance: ...dao.impl.TheRepository#61230f6a
Caused by: Missing invocations
at ...dao.impl.TheRepository.nameExists(TheRepository.java)
I see what the issue is in this case. The error message now makes sense. In this particular test, the method that is missing the invocation is not actually called because of the code path the test takes based on the the parameters. So the Expectations block must only contain mocking behavior for code that actually WILL BE EXECUTED. Now I understand
As the title states, I can call verifyPrivate but it always gives me success even if I pass the wrong parameters to it.
Real example
#RunWith(PowerMockRunner.class)
#PrepareForTest({MyService.class})
public class MyServiceTest {
#InjectMocks
MyService service;
#Mock
OperationSivRepo operationSivRepo;
#Test
public void getNbInscriptions_should_call_getNbOperationsSiv_with_OPERATION_INSCRIPTION_GAGE() throws Exception {
// GIVEN
Role role = Role.ADMINISTRATEUR;
String operator = "operator";
SivDto sivDto = new SivDto();
// WHEN
service.getNbInscriptions(operator, role, sivDto);
// THEN
verifyPrivate(service).invoke("privateMethod", operator, Role.ADMINISTRATEUR, sivDto);
}
}
Now this code will succeed, even if I do something like
// THEN
verifyPrivate(service).invoke("privateMethod", "other string", Role.USER, new SivDto());
Maybe I'm missing something but I just can't figure it out.
Firstly. Did you put a debug point in privateMethod and see how many times it is getting called? This would have given you some hint.
It is getting called two times. Once when you call
service.getNbInscriptions(operator, role, sivDto);
and once when you use
verifyPrivate(service).invoke("privateMethod", operator, Role.ADMINISTRATEUR, sivDto);
Second time since it is getting called with the arguments you passed to invoke method, the tests always succeed.
Use Spy instead of Mock
Instead of
#InjectMocks
MyService service;
Use
#Spy
MyService myservice = new MyService(operationSivRepo)
Wiht this, second invocation to the method is not made and arguments are verified properly.
How to get constructor injection in Mockito
I have the following class:
class A {
private B mB;
A(B b) {
mB = b;
}
void String someMethod() {
mB.execute();
}
}
how do I test someMethod using a mock class A and class B using
B b = Mockito.mock(B.class)
Mockito.when(b.execute()).thenReturn("String")
A a = Mockito.mock(A.class)
//somehow inject b into A and make the below statement run
Mockito.when(a.someMethod()).check(equals("String"))
You need create real A class because you want to test it but you need to mock other classes used in A class. Also, you can find mockito documentation says that don't mock everything.
class ATest {
#Mock
private B b;
private A a;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
a = new A(b);
}
#Test
public String someMethodTest() {
String result = "result";
Mockito.when(b.execute()).thenReturn(result);
String response = a.someMethod();
Mockito.verify(b, Mockito.atLeastOnce()).execute();
assertEquals(response, result);
}
}
Another way of injecting a mock to real object (as A should be a real object) is to use annotations, they will create objects you want:
#Mock
B mockOfB;
#InjectMocks
A realObjectA;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
Then, like they said, run the method you want to test without mockito (because you want to test it, so call it on real instance) and check the result according to your expectations.
Behaviour of object B can be mocked in any way, to satisfy your needs.
You want to test someMethod() of class A. Testing the execute() of class B should take place in the other test, because instance of B is a dependency in your case. Test for execute() should be made in different test.
You don't need to test how B object will behave, so you need to mock it and afterwards, check that execute() was invoked.
So in your case your test will look something like this:
B b = Mockito.mock(B.class);
A a = new A( b );
a.someMethod();
Mockito.verify( b, Mockito.times( 1 ) ).execute();
In my opinion, you're mixing up two ways of testing.
If you want to write a test using Mockito, you just create a mock of some class and use it. This mock doesn't have anything related to a real object as you can (should) mock every method that is called in the test. That's why it doesn't make any sense to mock class B - it is simply not used by class A.
Otherwise, if you want to test a real behavior of class A then why do you want to mock it? Create a real instance of class A with a mocked instance of class B.
That's it! Don't mix it up.
I have got a problem with testing how many times concrete methods (IFunction in the Operation instance) is invoked.
According to:
http://easymock.org/user-guide.html#mocking-annotations
http://www.ibm.com/developerworks/library/j-easymock/
How to use EasyMock expect
I wrote something as:
class Operation{
public double[] calculateSth(IFunction function, int [] t){
for(int i=0 ; i<5 ; i+=1)
function(t, new int[]{1,2,3});
return new double[]{1,2,3};
}
}
interface IFunction{
double f(int[] a, int[]b);
}
class ConcreteF implements IFunction{
double f(int[]a, int[]b){
return 5;
}
}
And my test class:
#TestSubject
Operation op;
#Mock
IFunction function;
#Before
public void setUp() throws Sth{
op=new Operation();
function = EasyMock.createMock(IFunction.class);
}
#Test
public void howManyTimes(){
EasyMock.expect(function.f(EasyMock.notNull(), EasyMock.notNull())
)
.andReturn((double)EasyMock.anyDouble()).times(3);
EasyMock.replay(function);
op.calculateSth(function, new double[]{0,0,0});
//verify
EasyMock.verify(function);
}
Result:
java.lang.NullPointerException
at org.easymock.internal.Injector.injectMocks(Injector.java:80)
at org.easymock.EasyMockSupport.injectMocks(EasyMockSupport.java:624)
at org.easymock.EasyMockRunner.withBefores(EasyMockRunner.java:50)
It's my first time using easymock and i don't know how to fix it ;/
I'll answer this question without going into the details of whether the original method does anything useful (the code doesn't even compile anyway), let alone the test method.
#TestSubject Operation op;
This line is a suspect. I realize that you are instantiating it in the #Before annotated setUp method, but it looks like the Easymock tries to inject the mocks (the ones annotated with #Mock) before it does anything (and understandably so) and blows up since the reference is null at that point.
The annotation support introduced in v3.2 is also seen as a way to eliminate the need for setUp method. But you seem to be mixing both and using it wrongly. Choose one or the other - I'd recommend you to use the annotations.
Quoting the Easymock user guide (this user guide is as good as it can ever be, so be sure read this up before using the library),
#RunWith(EasyMockRunner.class)
public class ExampleTest {
#TestSubject
private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2
#Mock
private Collaborator mock; // 1
#Test
public void testRemoveNonExistingDocument() {
replay(mock);
classUnderTest.removeDocument("Does not exist");
}
}
The mock is instantiated by the runner at step 1. It is then set by
the runner, to the listener field on step 2. The setUp method can be
removed since all the initialization was done by the runner.