Unit Testing: Testing a class which has an outside method - java

class A {
int a;
public int add() {
B b = new B();
a = b.calculate(4, 5);
return a;
}
}
class B {
public int calculate(int x, int y) {
return x * y;
}
}
I want to test class A, where and did not want to test the b.calculate() in the add() method.
So I need to mock the class B.
Here is my code.
#Mock
B bclass;
A aclass;
#Before
public void setUp() {
bclass = new B();
aclass = new A();
}
#Test
public void testAClass() {
when(bclass.calculate(4, 5)).thenReturn(45);
assertEquals(45, aclass.add());
}
The test getting failed. What's wrong with it?

It looks like you are using Mockit framework.
You could try doing the following:
new MockUp<B>() {
#Mock
int calculate(int x, int y) // no access modifier required
{
return 45; // your value
}
};

The #Mock annotation already generates the instance of the B. We do not need to create instance again here. Also, make sure you are annotating with Valid Runner or using the Rule.
#RunWith(MockitoJUnitRunner.class)
Let us know the error shown if it is not working. You can also refer the below link on using mockito.
http://www.vogella.com/tutorials/Mockito/article.html#mockito_usage

Your problem is the hidden dependency of class A to class B.
The answer of #Jens showed you how to solve this with PowerMock but I concider this as a surrender to your bad design.
The better was is to make this dependency explicit by injecting an instance of class B into objects of class A preferably as Constructor parameters.
Preferably using a dependency injection framework like guice or spring.
the you can use regulat Mockito constructs.
class A {
int a;
private final B b;
public A(B b){
this.b=b;
}
public int add() {
a = b.calculate(4, 5);
return a;
}
}
#Mock
B bclass;
A aclass;
#Before
public void setUp() {
aclass = new A(bclass);
}
#Test
public void testAClass() {
when(bclass.calculate(4, 5)).thenReturn(45);
assertEquals(45, aclass.add());
}

I am not sure if it is possible with Mockito. With PowerMockito it works:
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.class)
public class BTest {
A aclass;
B bMock;
#Before
public void setUp() throws Exception {
bMock = PowerMockito.mock(B.class);
PowerMockito.whenNew(B.class).withNoArguments().thenReturn(bMock);
aclass = new A();
}
#Test
public void testAClass() {
Mockito.when(bMock.calculate(4, 5)).thenReturn(45);
Assert.assertEquals(45, aclass.add());
}
}

Related

Using reflection in a Spy class

I have the following scenario.
public class A {
//constructors
#Value(${useMethodA:false})
private boolean isUseMethodAEnabled;
public void func() {
if(isUseMethodAEnabled()) {
a();
} else {
b();
}
}
}
//methods a() and b()
public class B {
#Autowired
private A a;
public void funcPrincipal() {
A.a();
System.out.println("Method A.a() was called");
}
}
#RunWith(MockitoJUnitRunner.class)
public class BTest {
#InjectMocks
private B b;
#InjectMocks
#Spy
private A a = new A();
#Test
public void test() {
ReflectionTestUtils.setField(a, "isUseMethodAEnabled", true);
b.funcPrincipal();
// if A is annotated with #Spy -> the "isUseMethodAEnabled" is always false
}
}
See the above comment, please.
Is there any solution to change the "isUseMethodAEnabled" value from false to true using reflection?
If I switch to #Mock instead of #Spy everything works as expected. But for my test cases, I must use #Spy + #InjectMocks.

Mocking new object method call in Junit5

I have mocked another class method called Which is called at production like new B().somemethod (arg) has return type void and newD().anymenthod() it has return type inputstream
In the test method, I am doing mocking Like donothing().when(b). somemethod ();
And
When(d.anymehod()).thenreturn(inputstream);(here inputstrem i am providing)
Here I already did #Mock B b;
#Mock D d;
Here my test case run successfully but mocked method was also called at that time.
Here I didn't want to alter the production code only test cases implementation can be altered.
class TestSystem {
#InjectMock
System sys;
#Mock
B b;
#Mock
D d;
#BeforeEach
void setup() {
MockitoAnnotation.openMocks(this);
}
#Test
testModule() {
InputStrem input = null;
when(d.anymethod()).thenReturn(inputStrem);
doNothing().when(b).somemethod();
sys.module();
}
Class System{
public void module() {
//some code .....
new B().somemethod();
inputStrem = new D().anymethod(value);
}
Class B {
public void somemethod(){
//some code .....
}
}
Class D {
public InputStrem anymethod() {
//some code ......
}
}
Try to initialise Mock like this:
#InjectMocks
private System sys;
#Mock
B b;
#Mock
D d;
private AutoCloseable closeable;
#BeforeEach
void init() {
closeable = MockitoAnnotations.openMocks(this);
}
#AfterEach
void closeService() throws Exception {
closeable.close();
}
#Test
testModule(){...}

How to inject lambda method in constructor?

Testing class
stream list into map, where I get atribute from an element of this list
public class MyClass {
private final Map<String, IMyInterface> map;
public MyClass(final List<IMyInterface> list) {
this.map = list.stream().collect(Collectors.toMap(IMyInterface::getUniqueName, i -> i));
}
}
Test
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#InjectMock
private MyClass instance;
#Spy
private ArrayList<IMyInterface> list;
#Mock
private A a;
#Mock
private B b;
#Before void setUp() throws Exception {
list.add(a);
list.add(b);
}
}
Or Test
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Spy
private ArrayList<IMyInterface> list;
#Mock
private A a;
#Mock
private B b;
private class MockedClass extends MyClass {
MockedClass(List<IMyInterface> list) {
super(list);
}
}
#Before void setUp() throws Exception {
list.add(a);
list.add(b);
}
}
How to get injected Map after execute constructor? I have to test this class and use map object
EDIT:
IMyInterface::getUniqueName()
is a method in interface
objects A and B implements IMyInterface
I want to collect injected list into map
When I add elements into list, I got it in debugging mode in my tested class, but when debugging mode is on
list.stream().collect(Collectors.toMap(IMyInterface::getUniqueName(), i -> i));
it stop
The correct answer is that should I mock A and B in my #Before
private A a;
private B b;
#Before
public void setUp() throws Exception {
a = new A(mock.Service.class); // cause it have an argument
b = new B(mock.Service.class); // cause it have an argument
list.add(a);
list.add(b);
}

Prevent calling constructor - Mockito

Let's say I have classA and classB:
public class A {
private B b;
public A(String id){
this.b = new B(id);
}
public void doSomethingA(String id){
// do somethingA
}
}
public class B{
public B(String id){
// call anotherThing (id)
}
public void doSomethingB(){
//somethingB
}
}
now I want to test methods inside classA (with it's instance) but wanna mock classB
Mockito allows me to mock classB, but when I instantiate classA, the constructor calls classB (which I want to avoid)
Is there a way to mock only the constructor (either classA or classB) but not the other methods?
You may mock any B object but you don't want to.
You want to mock the B b field of the A class.
Which is different.
You have to refactor your design and do B instantiation a dependency and not an internal processing.
A simple way is passing directly the B variable instead of the String as parameter :
public class A {
private B b;
public A(B b){
this.b = b;
}
public void doSomethingA(String id){
// do somethingA
}
}
Now mocking is straight :
#Mock B b;
public void test(){
A a = new A(b);
}
An alternative way would be using a Function<String, B> .
public class A {
private B b;
public A(Function<String, B> bFunction, String id){
this.b = bFunction.apply(id);
}
public void doSomethingA(String id){
// do somethingA
}
}
Mocking becomes so :
#Mock B b;
public void test(){
A a = new A(s-> b, "anyValue");
}
And implementation code could instantiate A as :
A a = new A(B::new, "id");

unit testing a method that takes a list as an argument

I need to test a method that is taking a list as an argument. Below is the sample code:
public class C
{
private int x;
private String y;
//getters and setters
}
public class B
{
public void collectC(List<C> cList)
{
for(C c : cList)
{
System.out.println("int: " + c.getX() + "String: "+ c.getY());
}
}
}
So class B is simply collecting objects of class C and iteration on it using enhanced for loop.
Now, I want to test a method of class B. Below is the testing code.
public class BTest
{
private List<C> cList;
#Mock private C c;
#InjectMocks private B b;
#Before
public void setUp()
{
cList = new ArrayList<>();
cList.add(c);
MockitoAnnotations.initMocks(this);
}
#Test
public void testCollectC()
{
Mockito.when(c.getX()).thenReturn(5);
Mockito.when(c.getY()).thenReturn("Hello There");
b.collectC(cList);
}
}
So, this is giving me error NullPointerException on System.out.println() one line where I am invoking methods on 'c' object.
I then changed the code where I mocked a list and iterator too, so now my code is working fine. But I want to know that what is the problem with above-mentioned code and why it is failing?
You have to instance c before you add it to cList otherwise cList contains a null element.
The following test passes:
public class BTest {
private List<C> cList;
#Mock
private C c;
#InjectMocks
private B b;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
cList = new ArrayList<>();
cList.add(c);
}
#Test
public void testCollectC() {
Mockito.when(c.getX()).thenReturn(5);
Mockito.when(c.getY()).thenReturn("Hello There");
b.collectC(cList);
}
}

Categories

Resources