I am writing JUnit for a class that references a legacy class via constructor. The legacy class is in a third party jar, so I can't refactor it to make life easier....
This is the class being tested...
public MyClass {
public String methodToTest(String param) {
LegacyClass legacy = new LegacyClass(param);
*..... etc ........*
}
}
This is what I am trying to do in the mockito JUnit.
public MyClassTest {
#Test
public void testMethodToTest() throws Exception {
LegacyClass legacyMock = mock(LegacyClass.class);
when(*the LegacyClass constructor with param is called*).thenReturn(legacyMock);
*.... etc.....*
}
}
Any ideas on how I can do this ?????
Make a builder for the LegacyClass:
public class LegacyClassBuilder {
public LegacyClass build(String param) {
return new LegacyClass(param);
}
}
That way your class can be tested so it creates the LegacyClass with correct parameter.
public MyClass {
private LegacyClassBuilder builder;
public setBuilder(LegacyClassBuilder builder) {
this.builder = builder;
}
public String methodToTest(String param) {
LegacyClass legacy = this.builder.build(param);
... etc
}
}
The test will look something like this:
// ARRANGE
LegacyClassBuilder mockBuilder = mock(LegacyClassBuilder.class);
LegacyClass mockLegacy = mock(LegacyClass.class);
when(mockBuilder.build(anyString()).thenReturn(mockLegacy);
MyClass sut = new MyClass();
sut.setBuilder(mockBuilder);
String expectedParam = "LOLCAT";
// ACT
sut.methodToTest(expectedParam);
// ASSERT
verify(mockBuilder).build(expectedParam);
If LegacyClass happens to be final then you need to create non-final wrapper for LegacyClass that MyClass will use.
You can use PowerMockito framework:
import static org.powermock.api.mockito.PowerMockito.*;
whenNew(LegacyClass.class)
.withParameterTypes(String.class)
.withArguments(Matchers.any(String.class))
.thenReturn(new MockedLegacyClass(param));
Then write your MockedLegacyClass implementation according to your test needs.
I believe it is not possible to mock constructors using Mockito. Instead, I will suggest the following approach:
public MyClass {
public String methodToTest(String param) {
if(legacy== null){
//when junit runs, you will get mocked object (not null), hence don't initialize
LegacyClass legacy = new LegacyClass(param);
}
*..... etc ........*
}
}
public MyClassTest {
#InjectMock
Myclass myclass; // inject mock the real testable class
#Mock
LegacyClass legacy
#Test
public void testMethodToTest() throws Exception {
// when(legacy-constructor).thenReturn() ---not Required
// instead directly mock the required methods using mocked legacy object
when(legacy.getSomething(Mockito.any(String.class))).thenReturn(null);
*.... etc.....*
}
}
Related
Currently I am using JUnit5 for creating test cases in Java. But in some places I could not implement the test cases due to Mock issue.
This is my interface:
public interface EntityLookup extends Lookup {
public static final Constants constants = new Constants();
public static class Constants {
public EntityLookup VERIFY;
public void initialize() {
this.VERIFY = (EntityLookup)LookupHelper.getLookupInstance(EntityLookup.class, "ABCD");
}
}
}
I want to mock the below code
EntityLookup.constants.VERIFY.trimmedValue()
I know how to implement in JUnit4
#RunWith(PowerMockRunner.class)
public class MyTestClass {
#Test
public void test1() throws Exception {
PowerMockito.mockStatic(EntityLookup.class);
PowerMockito.mockStatic(EntityLookup.Constants.class);
EntityLookup.Constants constants = Mockito.mock(EntityLookup.Constants.class);
EntityLookup entityLookup = Mockito.mock(EntityLookup.class);
PowerMockito.whenNew(EntityLookup.Constants.class).withNoArguments().thenReturn(constants);
Whitebox.setInternalState(EntityLookup.constants, "VERIFY", entityLookup);
Mockito.when(entityLookup.trimmedValue()).thenReturn("ABCD");
//assert...
}
}
But in JUnit5, I have no idea
Can anyone convert it to JUnit5 from JUnit4?
I have a spring boot app with autowired components. It works fine operationally, but mocking is not initializing the components properly. Here are the main components:
base processor:
#Component
public class Processor {
public String getType() { return null; }
public void transformInput(JsonObject data) { }
public void buildOutputRequest(String syncType) { }
}
, one of the 4 subtypes:
#Component
public class ProcessorType1 extends Processor {
#Override
public String getType() { return Type.TYPE1.getValue();}
public void transformInput(JsonObject data) {
// do dtuff
}
}
, supporting enum:
public enum Type {
TYPE1("TYPE1"),TYPE2("TYPE2"), TYPE3("TYPE3"), TYPE4("TYPE4");
private final String value;
public static final Map<Type, String> enumMap = new EnumMap<Type, String>(
Type.class);
static {
for (Type e : Type.values())
enumMap.put(e, e.getValue());
}
Type(String value) { this.value = value;}
public String getValue() { return value; }
}
,and the factory class:
#Component
public class ProcessorFactory {
#Autowired
public ProcessorFactory(List<Processor> processors) {
for (Processor processor : processors) {
processorCache.put(processor.getType(), processor);
}
}
private static final Map<String, Processor> processorCache = new HashMap<String, Processor>();
public static Processor getProcessor(String type) {
Processor service = processorCache.get(type);
if(service == null) throw new RuntimeException("Unknown type: " + type);
return service;
}
}
, then operationally, a calling service uses the factory similar to this:
#Service
MyService {
public processData (
// do stuff to get processor type and data
Processor processor = ProcessorFactory.getProcessor(type);
processor.transformInput(data);
)
}
Again, operationally this works fine. However, I attempt to mock the factory and its initialization like the following:
#RunWith(SpringJUnit4ClassRunner.class)
public class ProcessorFacTest
{
#InjectMocks
ProcessorFactory factory;
#Test
void testGetSyncProcessorDocument() {
String type = Type.TYPE1.getValue();
Processor processor = ProcessorFactory.getProcessor(type);
Assert.assertTrue(processor instanceof ProcessorType1);
}
}
My expectation was that since I am using #InjectMocks, and since ProcessorFactory has its constructor autowired, the constructor would be called by InjectMocks as part of the initialization. However, this is not happening. The processorCache is zero-length because the constructor is never called.
I realize I am mixing injection with static usages, but since it worked operationally, and since my understanding was that InjectMocks would handle the creation of the processorCache, that it should have worked for the test class as well, and its not.
I would be grateful for any ideas as to what I am doing wrong. Thank you
You never define any mocks that could be injected. Which dependencies should be autowired if you don't define any? The constructor is still called, but with an empty list of dependencies (use your debugger to set a breakpoint there and check for yourself).
It's also critical to note that mocks will return null, empty lists or 0/false by default for all methods, unless the mock has been set up properly.
You must define the mocks so that they can be picked up by #InjectMocks plus use the correct JUnit runner/extension:
#ExtendWith(MockitoExtension.class) // JUnit 5
// #RunWith(MockitoJUnitRunner.class) // JUnit 4
public class ProcessorFacTest
{
#Mock
ProcessorType1 processor1;
#Mock
ProcessorType2 processor2;
// ...
#InjectMocks
ProcessorFactory factory;
#BeforeEach // JUnit 5
// #Before // JUnit 4
void setup() {
Mockito.when(processor1.getType()).thenReturn(Type.TYPE1);
Mockito.when(processor2.getType()).thenReturn(Type.TYPE2);
}
#Test
void testGetSyncProcessorDocument() {
String type = Type.TYPE1.getValue();
Processor processor = ProcessorFactory.getProcessor(type);
Assert.assertTrue(processor instanceof ProcessorType1);
}
}
EDIT: the above won't work because the processors are not a direct dependency for your class under test, but are elements of a list. Mockito will not be able to inject the correct mocks.
And here's how you would write the test as a Spring test with mock beans:
#RunWith(SpringJUnit4ClassRunner.class)
public class ProcessorFacTest
{
#MockBean
ProcessorType1 processor1;
#MockBean
ProcessorType2 processor2;
// ...
#Autowired
ProcessorFactory factory;
#BeforeEach // JUnit 5
// #Before // JUnit 4
void setup() {
Mockito.when(processor1.getType()).thenReturn(Type.TYPE1.getValue());
Mockito.when(processor2.getType()).thenReturn(Type.TYPE2.getValue());
}
#Test
void testGetSyncProcessorDocument() {
String type = Type.TYPE1.getValue();
Processor processor = ProcessorFactory.getProcessor(type);
Assert.assertTrue(processor instanceof ProcessorType1);
}
}
But actually you don't need to use any annotations here, you could wire the dependencies manually just as simple:
public class ProcessorFacTest
{
ProcessorFactory factory;
#BeforeEach // JUnit 5
// #Before // JUnit 4
void setup() {
final ProcessorType1 processor1 = Mockito.mock(ProcessorType1.class);
final ProcessorType1 processor2 = Mockito.mock(ProcessorType2.class);
Mockito.when(processor1.getType()).thenReturn(Type.TYPE1);
Mockito.when(processor2.getType()).thenReturn(Type.TYPE2);
factory = new ProcessorFactory(
List.of(
processor1,
processor2,
// ...
));
}
#Test
void testGetSyncProcessorDocument() {
String type = Type.TYPE1.getValue();
Processor processor = ProcessorFactory.getProcessor(type);
Assert.assertTrue(processor instanceof ProcessorType1);
}
}
If your processors are simply, easy to instantiate and don't depend on other classes, it might even be simpler (and better, YMMV) to simply use the real collaborators instead of mocks.
And it might be easier to create a test implementation of your processor type, which can be easier to set up than a mock object created dynamically with Mockito. The code would look like this:
#BeforeEach // JUnit 5
// #Before // JUnit 4
void setup() {
factory = new ProcessorFactory(
List.of(
new TestProcessor(Type.TYPE1),
new TestProcessor(Type.TYPE2),
// ...
));
}
private static class TestProcessor extends Processor {
private final Type type;
public TestProcessor(final Type type) { this.type = type; }
public String getType() { return type.getValue(); }
// Base class methods do nothing already. If they were, you would override them here with an empty implementation:
#Override
public void transformInput(JsonObject data) { /* do nothing */ }
#Override
public void buildOutputRequest(String syncType) { /* do nothing */ }
}
NB. It's bad practice to use names that are already defined in the JDK. Type is one such name (java.lang.reflect.Type).
It might also be worthwhile to read Why is my class not calling my mocked methods in unit test? to get a good overview of common gotchas when setting up mocks.
My FixValueConceptIntegration class has a constructor and it looks like this:
private ReferenceConceptHelper referenceConceptHelper;
private ConceptClientFacade conceptClientExternalFacade;
public FixValueConceptIntegration()
{
referenceConceptHelper = JournalSingletonFactory.getInstance().getSingletonInstance(ReferenceConceptHelper.class);
conceptClientExternalFacade = JournalSingletonFactory.getInstance().getSingletonInstance(ConceptClientFacade.class);
}
So now I'm going to test it using Mockito.
If we have a constructor like
public FixValueConceptIntegration(ReferenceConceptHelper referenceConceptHelper, ConceptClientFacade conceptClientExternalFacade)
{
this.referenceConceptHelper = referenceConceptHelper
this.conceptClientExternalFacade = conceptClientExternalFacade
}
I know it is easy to initialize when we are going to testing the class. Because we can just mock the ReferenceConceptHelper and ConceptClientFacade classes.
Then we can use it at the #BeforeMethod like this:
#BeforeMethod
public void beforeMethod()
{
MockitoAnnotations.initMocks(this);
fixValueConceptIntegration = new FixValueConceptIntegration(referenceConceptHelper, conceptClientExternalFacade);
}
Then all the dependencies will inject to the constructor and no worries.
So here the problem is I can't figure out how to inject these dependencies (by mocking) to the above testable class.
Just use the mock (org.mockito.Mockito.mock) method for the class and the when method to mock the method calls:
#Test
public void yourTest() {
ReferenceConceptHelper referenceConceptHelper = mock(ReferenceConceptHelper .class);
when(referenceConceptHelper.someMethod(any()).thenReturn("hello");
ConceptClientFacade conceptClientExternalFacade = mock(ConceptClientExternalFacade.class);
when(conceptClientExternalFacade.someMethod(any()).thenReturn("world");
FixValueConceptIntegration integration = new FixValueConceptIntegration(referenceConceptHelper, conceptClientExternalFacade);
assertEquals("hello world", integration.methodThatYouWouldLikeToTest());
}
In this case, you do not need to use the #BeforeMethod or call MockitoAnnotations.initMocks(this);. For unit tests, the initMocks are only useful if you do not have access directly to the class injected (typically when you are using field injection).
But if you would like to use the annotations (I personally don't like), you can do something like that:
#InjectMocks
private FixValueConceptIntegration integration;
#Mock
private ReferenceConceptHelper referenceConceptHelper;
#Mock
private ConceptClientFacade conceptClientFacade;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
when(referenceConceptHelper.someMethod(any()).thenReturn("hello");
when(conceptClientExternalFacade.someMethod(any()).thenReturn("world");
}
#Test
public void yourTest() {
assertEquals("hello world", integration.methodThatYouWouldLikeToTest());
}
I extended my test class with TestNGBase which extends PowerMockTestCase.
And then add registerMockSingleton method to the TestNGBase class like this;
protected <E, I extends E> void registerMockSingleton(Class<E> typeInterface, I mock)
{
delegate.registerMockSingleton(typeInterface, mock);
}
Then inject mock dependencies to the constructor like this way;
#Override
public void performSetup() {
MockitoAnnotations.initMocks(this);
registerMockSingleton(ReferenceConceptHelper.class,mockReferenceConceptHelper);
registerMockSingleton(ConceptClientFacade.class,mockConceptClientExternalFacade);
fixValueConceptIntegration = new FixValueConceptIntegration();
}
#Override
protected void performTearDown() throws Exception
{
fixValueConceptIntegration = null;
}
All solved!!!
(My testable class constructor doesn't inject dependencies to with constructor
arguments.Thats why I solved my problem like this)
I have a method to test which is calling another class to get some information:
public ClassToTest {
public void methodToTest() {
AnotherClass ac = Factory.getInstance();
ResponseObj response = ac.anotherMethod();
}
}
AnotherClass is part of another JAR and I would like to mock the response from it(to be specific mock ResponseObj response)
How can I achieve that using Mockito?
First you need is to make your class testable. It means you need to extract object creation (AnotherClass ac = Factory.getInstance()) from your methodToTest to instance field or maybe separate method (to be able to mock it), or even better - create object outside of your class and pass it via constructor. As a result, your class under test should look like:
public class ClassToTest {
private AnotherClass ac;
public ClassToTest(AnotherClass ac) {
this.ac = ac;
}
public void methodToTest() {
ResponseObj response = ac.anotherMethod();
response.smth();
}
}
Then you need to declare AnotherClass and ResponseObj as fields in test class, and initialize them as a mocks.
AnotherClass ac = Mockito.mock(AnotherClass.class);
ResponseObj responseMock = Mockito.mock(ResponseObj.class);
After that you can mock method call:
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
At the end your test class should look like:
public class ClassToTestTest {
private AnotherClass anotherClassMock = mock(AnotherClass.class);
private ResponseObj responseMock = mock(ResponseObj.class);
private ClassToTest classToTest = new ClassToTest(anotherClassMock);
#Test
public void test() {
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
classToTest.methodToTest();
verify(responseMock, only()).smth();
}
}
And in case you couldn't change public API of your ClassToTest, you can use approach with Mockito spy and protected method.
public class ClassToTest {
public void methodToTest() {
AnotherClass ac = constructAnotherClassObj();
ResponseObj response = ac.anotherMethod();
response.smth();
}
protected AnotherClass constructAnotherClassObj() {
return Factory.getInstance();
}
}
public class ClassToTestTest {
private AnotherClass anotherClassMock = mock(AnotherClass.class);
private ResponseObj responseMock = mock(ResponseObj.class);
private ClassToTest classToTest = spy(new ClassToTest());
#Test
public void test() {
when(anotherClassMock.anotherMethod()).thenReturn(responseMock);
when(classToTest.constructAnotherClassObj()).thenReturn(anotherClassMock);
classToTest.methodToTest();
verify(responseMock, only()).smth();
}
}
Although the answer by #arsen_adzhiametov is correct and up to the mark I would like to contribute how I do it.
In this case, I am mocking the value of HomeClient which internally is a WebClient that calls out another service for some values.
TestClass.java (Please name it better)
...
import org.mockito.Mockito;
...
class TestClass {
HomeClient mockHomeClient;
#BeforeEach
void setup() {
mockHomeClient = Mockito.mock(HomeClient.class);
// Axon specific test code. Can ignore if not using Axon.
fixture = new AggregateTestFixture<>(SomeAgreegate.class);
fixture.registerInjectableResource(mockHomeClient);
}
#Test
void testOpenOperation() throws HomeClientException {
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(2);
// Do what you will with your code and call the method which you want to test
// Mockito will mock the `HomeClient` in this case and `getXYZ` will return `2`
// You can also change the mock response any time in the same function
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(-100);
// Or specify different results on mock when different values are provided
Mockito.when(mockHomeClient.getXYZ("nice")).thenReturn(1);
Mockito.when(mockHomeClient.getXYZ("foo")).thenReturn(100);
Mockito.when(mockHomeClient.getXYZ("bar")).thenReturn(0);
}
}
I want to replace an autowired class of a service in my spring boot app with a mocked implementation of that class that I created specifically for testing.
I chose to create this mocked implementation because the behaviour of this class is too complicated to mock using mockito as it requires multiple other mocks itself.
I am not able to work out how to inject this mocked implementation into the service.
Here is a minimal example of the situation:
#Service
public class ServiceIWantToTestImpl implements ServiceIWantToTest{
#Autowired
ComplicatedDependency complicatedDependency;
#Override
public void methodUsingDependency(){
String string = complicatedDependency.doSomething();
System.out.println(string);
}
}
public class MockComplicatedDependency implements ComplicatedDepencency{
public MockComplicatedDependency(...){
// Inject other mocked objects into this mock
}
public String doSomthing(){
// This would be a mocked version of this function for testing
return "test";
}
}
#RunWith(MockitoJUnitRunner.class)
public class TestingTheService(){
#InjectMock
private static ServiceIWantToTest serviceIWantToTest = new ServiceIWantToTestImpl();
#Mock
ComplicatedDependency mockComplicatedDependency;
#BeforeClass
public static void init(){
mockComplicatedDependency = new MockComplicatedDependency(...);
}
#Test
public void testAttempt(){
serviceIWantToTest.methodUsingDependency(); // This method calls complicatedDependency.doSomething() which does not run the mocked version in MockComplicatedDependency which I wanted to inject, and would always return null instead of the "test" string I put in this example.
}
}
Do you have to use Mockito annotations to setup dependencies for the class under test?
If that is not the main constraint why not just do the plain simple setup and introduce a constructor or a setter in ServiceIWantToTestImpl class for the ComplicatedDependency field and set the dependency in your test setup directly to whatever impl of ComplicatedDependency you like e.g.:
#Service
public class ServiceIWantToTestImpl implements ServiceIWantToTest {
#Autowired
ComplicatedDependency complicatedDependency;
public ServiceIWantToTestImpl() {
}
public ServiceIWantToTestImpl(ComplicatedDependency complicatedDependency) {
this.complicatedDependency = complicatedDependency;
}
#Override
public void methodUsingDependency(){
String string = complicatedDependency.doSomething();
System.out.println(string);
}
}
public class TestingTheService {
private static ServiceIWantToTestImpl serviceIWantToTest;
#BeforeClass
public static void init(){
serviceIWantToTest = new ServiceIWantToTestImpl(new MockComplicatedDependency());
}
#Test
public void testAttempt() {
serviceIWantToTest.methodUsingDependency();
}
}
That is one way.
To make it work with Mockito, You could to use #Spy instead of #Mock like this:
#RunWith(MockitoJUnitRunner.class)
public class TestingTheService {
#InjectMocks
private static ServiceIWantToTestImpl serviceIWantToTest = new ServiceIWantToTestImpl();
#Spy
private static ComplicatedDependency complicatedDependency = new MockComplicatedDependency();
#BeforeClass
public static void init() {
}
#Test
public void testAttempt() {
serviceIWantToTest.methodUsingDependency();
}
}
Though this is a bit of a hack. I strongly recommend that you read the JavaDoc of the #Spy annotation and make sure it's expected use is what you really need for your test.