I am having one #Inject object which i need to mock its throwing NPE while using #InjectMocks at my test class
Below is the structure of my class
Class ChildClass extends ParentClass
{
public myMethod(){
String myval=callParentClassMethod();
}
Class ParentClass{
#Inject
private MyService myservice;
//there is no constructor or setter method for this injected object
protected String callParentClassMethod(){
retrun myservice.getStringval();
}
}
Can you please suggest how to mock this MyService object.I have used #Mock and #Injected mock but its not working getting NPE. i tried to inject in both Base class and parent class but no luck.
following works for me:
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#InjectMocks
private ChildClass childClass = new ChildClass();
#Mock
private MyService service;
#Test
public void test1() {
childClass.myMethod();
}
}
UPDATE
I've uploaded example project with test to https://github.com/shurick-k/mock-test
You've not specified exactly what type of #Inject annotation is used, so I assumed it is from javaee-api. Actually it does not matter.
Related
I'm using mokito to inject a mock. This object extends a class that requires a contructor with arguments. How to mock this object that requires constructor arguments and pass this arguments as mock too?
Example class
public abstract class AbstractClassRequireContructor{
protected AbstractClassRequireContructor(Object param) {
}
public class ClassA extends AbstractClassRequireContructor{
public ClassA(Object param) {
super(param); // required by super class
}
}
Test class
#ExtendWith(MockitoExtension.class)
public class ClassATest{
#Mock
private Object paramMockToBeAddedByConstructor;
#InjectMocks
private ClassA classA; // requires contructor from super class
#BeforeEach
void setup{
when(paramMockToConstructor.anyMethod()).thenReturn(anyValue);
// how to inject mocked argument?
classA = new ClassA(paramMockToBeAddedByConstructor); // this doesn't work
}
#Test
void test(){
when(classA.anyMethod()).thenReturn(anyValue); // use injectMock class normally
}
}
Is there any another strategy to work arroung this better?
Drop the instantiation of a new ClassA object. It should work without it as follows:
#ExtendWith(MockitoExtension.class)
public class ClassATest{
#Mock
private Object paramMockToBeAddedByConstructor;
#InjectMocks
private ClassA classA;
#BeforeEach
void setup{
when(paramMockToConstructor.anyMethod()).thenReturn(anyValue);
}
#Test
void test(){
when(classA.anyMethod()).thenReturn(anyValue);
}
}
I'm using spring-boot-starter-test 2.2.0 which includes Mockito 3.1.0.
I would like to test this class:
#RestController
public class MyClass {
#Autowired MyAutowired myAutowired;
public int myClassMethod(int i) {
return myAutowired.methodToMock(i);
}
}
Which use this one:
#Service
public class MyAutowired {
public int methodToMock(int i) {
return i;
}
}
In my test I would like to run myClassMethod but with a mocked behavior for methodToMock. Ideally I would like to check if methodToMock was called with the expected argument.
Here is what I tried so far:
#SpringJUnitConfig(Config.class)
#WebAppConfiguration
#ExtendWith(MockitoExtension.class)
class MyClassTest {
#Autowired MyClass myClass;
#Mock
private MyAutowired myAutowired;
#BeforeEach
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
#Test
public void myTest() {
Mockito.when(myAutowired.methodToMock(any()).thenReturn(1);
int shouldBe1ButIs2 = myClass.myClassMethod(2);
}
}
What's wrong with that ? And how to make myClass.myClassMethod(2) return 1 ?
The issue is that your object MyClass is not referring to the right mock instance. The MyAutowired has to injected into MyClass.
You have two options:
Creating a setMyAutowired method in MyClass and pass the MyAutowired instance to it in your test class.
Replacing #Autowired with #InjectMocks annotation on MyClass. In this way, an instance of MyClass will be created and mocks objects which you declared in your test will be injected automatically in it.
I normally use the second option, which is more elegant.
I'm using Mockito in a Java project with Spring and Struts and I'm having problems with testing actions.
I'm not using the Struts2 jUnit plugin to save time with the tests using this approach: Strut 2.3.1.2 Unit test, how to remove Spring codependency vs NPE with getContext().
The problem is when in my action, when getText() is called I've got a NullPointerException.
I'm trying to spy this method, that's inherited from ActionSupport but I don't find a way because the action is annotated with InjectMocks in the test.
Here's a simplied example of the classes:
Parent:
public class ActionSupport {
public String getText(String aTextName){
return this.getTextProvider().getText(aTextName);
}
}
My action:
public class MyAction extends ActionSupport {
#Autowired private IMyService myService;
public String execute(){
getText("SomeText");
myService.something();
return SUCCESS;
}
}
Test:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock private IMyService myService;
#InjectMocks private MyAction myAction;
#Before
public void before() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
myAction.execute();
}
}
I'm getting this exception:
java.lang.NullPointerException
at com.opensymphony.xwork2.util.TextParseUtil.translateVariables(TextParseUtil.java:167)
at com.opensymphony.xwork2.util.TextParseUtil.translateVariables(TextParseUtil.java:126)
at com.opensymphony.xwork2.util.TextParseUtil.translateVariables(TextParseUtil.java:48)
at com.opensymphony.xwork2.util.LocalizedTextUtil.getDefaultMessage(LocalizedTextUtil.java:663)
at com.opensymphony.xwork2.util.LocalizedTextUtil.findText(LocalizedTextUtil.java:534)
at com.opensymphony.xwork2.util.LocalizedTextUtil.findText(LocalizedTextUtil.java:362)
at com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:208)
at com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:123)
at com.opensymphony.xwork2.ActionSupport.getText(ActionSupport.java:103)
at es.MyAction.execute(MyAction.java:148)
And if I annotate MyAction with #Spy maintaining #InjectMocks I've got an StackOverflowError.
How can I spy only ActionSupport.getText() and let mockito inject mocks on my action?
I would avoid using #InjectMocks as it fails silently.
Just add a constructor to your MyAction still using #Autowired i.e. constructor injection. This also helps guarantee required dependencies.
You dont need both initMocks and MockitoJUnitRunner.
public class MyAction extends ActionSupport {
private IMyService myService;
#Autowired
public MyAction(MyService myService) {
this.myService = myService;
}
public String execute(){
getText("SomeText");
myService.something();
return SUCCESS;
}
}
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock
private IMyService myService;
private MyAction myAction;
#Before
public void setup() {
myAction = spy(new MyAction(myService));
}
#Test
public void test() {
assertThat(myAction.execute(), equalTo(Action.SUCCESS));
verify(myAction, times(1)).getText();
verify(myService, times(1)).something();
}
}
InjectMocks fails silently
Constructor injection discussion
I'm trying to write a test case for a java class. I've mocked a method using Mockito, but the mock is never being used. Why?
Below is the structure of my java class:
class A {
#Autowired
private ClassB classB;
publiv void methodOne() {
methodTwo();
}
private void methodTwo() {
...
int returnedValue = classB.someMethod();
...
}
}
The test class is given below:
class ATest {
#Mock
private ClassB classB;
#InjectMocks
#Autowired
ClassA classA;
#Before
public void setupTest() {
MockitoAnnotations.initMocks(this);
}
#Test(expected = SomeException.class)
public void testMethodOne() {
when(classB.someMethod()).thenReturn(29);
classA.methodOne();
}
}
The test class is extended from another which has the #RunWith(SpringJUnit4ClassRunner.class) annotation.
I've gone through the existing questions but have been unable to find an answer. If there is any question/answer that may help me, please point me to the same.
Thanks in advance!
You could try to remove #Autowired in your test class ATest.
#InjectMocks should be sufficient as it creates your test object and injects your mock.
Depending on your JUnit runner #Autowired might perform a second injection after #InjectMocks which overrides your mocked method setup.
First, a few notes on your test:
- the test should be public
- class A should be public
- there is no need for #Autowire in the test
- there is no need to call initMocks
Then, your test isn't actually testing if the mock is being used or not. Let's change these method so that they now return the value, so that we can test if they work or not:
public class ClassA {
#Autowired
private ClassB classB;
public int methodOne() {
return methodTwo();
}
private int methodTwo() {
return classB.someMethod();
}
}
public class ClassB {
public int someMethod() {
return 0;
}
}
We can now test:
#RunWith(MockitoJUnitRunner.class)
public class ATest {
#Mock
private ClassB classB;
#InjectMocks
ClassA classA;
#Test
public void testMethodOne() {
when(classB.someMethod()).thenReturn(29);
final int result = classA.methodOne();
assertEquals(29, result);
}
}
And the test passes - meaning the mock is being used correctly.
Hope that helps.
What you're missing is that annotations are just declarations. The #Mock and #InjectMocks annotations don't do anything. They are only markers that can be seen by the test runner to perform specific runner-specific behavior. You need a #RunWith annotation to specify a test runner, but you need a specific test runner for specific behavior. If you're using the SpringJUnit4ClassRunner, then none of the Mockito annotations will be used. In any case, I wouldn't want to use the SpringJUnit4ClassRunner for unit tests, as you should just be verifying business logic, not wiring.
Change your test class to use #RunWith(MockitoJUnitRunner.class) and remove the base class reference.
I have test class inheritance issue: putting #Mocked and #Injectable fields to common abstract test parent class breaks auto-injection of mocked instances to #Tested class.
I use JMockit 1.5.
Here's an example:
public MyService {
private MyStorage storage;
public void myMethod(String entityId){
storage.getEntity(entityId);
// ...
}
}
public abstract class AbstractTestBase {
#Injectable
protected MyStorage storage;
}
public class MyTest extends AbstractTestBase {
#Tested
private MyService tested;
#Test
public void test_myMethod(){
new Expectations() {
{
storage.getEntity("1");
result = "foobar";
}
tested.myMethod("1"); // <-- here I have NPE
// as storage is not injected properly.
// ...
};
}
}
If I move #Injectable MyStorage storage to MyTest class everything gets injected correctly to #Tested class.
How can I allow auto-injections with common parent for test classes?
I found out the issue is solved in the most up to date release 1.11.