Using reflection in a Spy class - java

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.

Related

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 mock a method call in a constructor?

I have class class1, which has 2 member variables:
classA
{
private Boolean isEnable;
private Config config;
public classA(final Config config)
{
this.config = config;
isEnable = config.getEnablingStatus();
}
public classB fun()
{
// Do something!
// Return an object of classB!
}
}
I want to test the method fun, so I will have to write a test-class and a test method for that. But, how do I mock the method call config.getEnablingStatus(), while creating an object of type classA in the test class?
I am thinking of doing something like this [see the below piece of code].Is it correct? But what is the right way to do it?
TestClassForClassA:
TestClassForClassA
{
private Boolean isEnable;
#Mock
private Config config;
#InjectMocks
classA objA = new classA(config);
#Before
public void init()
{
initMocks(this);
}
public void test1Fun()
{
// Does doing this, put the value of isEnable as true in the objA for this test?
isEnable = true;
// Here write the code to test the method fun().
}
public void test2Fun()
{
// Does doing this, put the value of isEnable as false in the objA for this test?
isEnable = false;
// Here write the code to test the method fun().
}
}
Do not use #InjectMocks
Try something like this
public class TestClassForClassA {
#Mock
private Config config;
private ClassA objA;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test1Fun() {
Mockito.when(config.getEnablingStatus()).thenReturn(true);
objA = new ClassA(config);
ClassB objB = objA.fun();
assertTrue(objB.isEnabled());
}
#Test
public void test2Fun() {
Mockito.when(config.getEnablingStatus()).thenReturn(false);
objA = new ClassA(config);
ClassB objB = objA.fun();
assertFalse(objB.isEnabled());
}
}

Is it possible to set tested class' method's return value in JUnit?

Say, there's the following class to be tested:
public class MyClass {
public void method1() {
...
String str = method3()
...
}
public int method2() {...}
private String method3() {...}
}
I'm writing MyClassTest.java with JUnit. I want method3() to return a value that I have assigned, not execute the method itself. I can only use Mockito.
Is it possible?
If yes, how do I do it?
With just Mockito you cannot mock a private method.
But you could refactor your code to extract method3() in another class as a public method that you could use as dependency of MyClass. In this way method3() is naturally mockable.
public class MyClass {
private Foo foo;
public MyClass(Foo foo){
this.foo = foo;
}
public void method1() {
...
String str = foo.method3()
...
}
public int method2() {...}
}
public class Foo {
public String method3() {...}
}
Now mock that in the unit test :
#Mock
Foo fooMock;
MyClass myClass;
#BeforeEach
void init(){
myClass = new MyClass(fooMock);
}
#Test
public void method1(){
Mockito.when(fooMock.method3()).thenReturn("dummy value");
// call method1()
// do assertions
}
You can't do it with Mockito, but you can with JMockit. Your test would look like this:
#RunWith(JMockit.class)
public class JMockitTest {
#Tested
private MyClass myClass;
#Before
public void setUp(){
myClass = new MyClass();
}
#Test
public void testMethod1(){
new MockUp<MyClass>() {
#Mock
String method3() {
return "dummy value";
}
};
myClass.method1();
// do assertions
}
}
You can read the documentation about this feature, called faking, here.

Jmockit #Mocked inside a helper class doesn't initialize

If I have the following;
public class ClassA {
public void methodA(){
System.out.println("In ClassA, methodA");
}
}
public class ClassB {
public void methodB(){
}
}
and a junit test of;
#Test
public void testMocked(#Mocked final ClassB mockedB) {
System.out.println("Mocked inline");
new MockUp<ClassA>() {
#Mock
public void methodA() {
System.out.println("Inline mockup, mockedB:" + mockedB);
}
};
ClassA a = new ClassA();
a.methodA();
}
Then when I run the test I get;
Mocked inline
Inline mockup, mockedB:jmockitpractice.ClassB#329b0985
Which is as expected, the classB is Mocked, and an instance is available.
But, if I change this to create a helper class for mocking,
public class MockHelper {
#Mocked ClassB classB;
public void setupMocks(){
new MockUp<ClassA>() {
#Mock
public void methodA(){
System.out.println("In setupMocks, classB:"+classB);
}
};
}
}
and the junit becomes;
#Test
public void testMockedInClass() {
System.out.println("Mocked in helper class");
MockHelper mh = new MockHelper();
mh.setupMocks();
ClassA a = new ClassA();
a.methodA();
}
the result I get is;
Mocked in helper class
In setupMocks, classB:null
classB is not initialized by the #Mocked inside MockHelper
I would like to have all the mocking in a helper class, rather than having to declare all the mocking in the test class.
Any ideas why this doesn't work?
Thanks.
Thanks Dom Farr, the answer was inheritance.
public class MockHelper {
#Mocked
ClassB classB;
public void setupMocks() {
new MockUp<ClassA>() {
#Mock
public void methodA() {
System.out.println("In setupMocks, classB:" + classB);
}
};
}
}
and
public class mockTest extends MockHelper {
#Test
public void testMockedInClass() {
System.out.println("Mocked in helper class");
setupMocks();
ClassA a = new ClassA();
a.methodA();
}
}
As the test class extends the helper, it now works;
Mocked in helper class
In setupMocks, classB:jmockitpractice.ClassB#5d54e317

Unable to mock while implementing builder pattern

I'm having hard time to test a class(TestClass) which uses builder pattern(BuilderClass) in logic . I'm unable to mock builder class(BuilderClass). The following is simplified version of my logic.
public class TestClass {
public int methodA() {
ExternalDependency e = BuilerClass.builder().withName("xyz").withNumber(10).build();
return e.callExternalFunction();
}
}
And here is my builder class
public class BuilderClass {
public static BuilderClass builder() { return new BuilderClass(); }
int number;
String name;
public BuilderClass withName(String name) {
this.name = name;
return this;
}
public BuilderClass withNumber(int number) {
this.number = number;
return this;
}
public ExternalDependency build() {
return new ExternalDependency(name,number);
}
}
For my test class, I'm using Mockito with Dataprovider.
#RunWith(DataProviderRunner.class)
class TestClassTest {
#Mock private ExternalDependency e;
#Mock private BuilderClass b;
#InjectMocks private TestClass t;
#Before public void setUp() { MockitoAnnotations.initMocks(this); }
#Test public void testMethodA() {
when(b.withName(any(String.class)).thenReturn(b); //This is not mocking
when(b.withNumber(10)).thenReturn(b); //This is not mocking
Assert.notNull(this.t.methodA()); //Control while execution is going to implementation of withName and withNumber, which should not happen right.
}
Help me if I miss anything. Thanks
}
Similar to what kryger said in a comment above, you probably need to do a refactor like this:
In your class under test, create a seam to replace e by a mock:
public class TestClass {
public int methodA() {
ExternalDependency e = buildExternalDependency("xyz", 10);
return e.callExternalFunction();
}
protected ExternalDependency buildExternalDependency(String name, int number) {
return BuilerClass.builder().withName(name).withNumber(number).build();
}
}
In the test code, override the test class to replace e with a mock and to validate the inputs to the builder:
#RunWith(DataProviderRunner.class)
class TestClassTest {
#Mock private ExternalDependency e;
private TestClass t;
#Before public void setUp() {
MockitoAnnotations.initMocks(this);
t = new TestClass() {
#Override
protected ExternalDependency buildExternalDependency(String name, int number) {
// validate inputs:
Assert.assertEquals(10, number);
Assert.assertEquals("xyz", name);
return e; // provide the mock
}
}
}
#Test public void testMethodA() {
// TODO: mock behavior of callExternalFunction() here
Assert.notNull(this.t.methodA());
}
}
You may want to go further with the refactor to move buildExternalDependency() into a another class which could be mocked and injected in the constructor of TestClass.

Categories

Resources