I'm using Mockito to create mock beans, and for some reason, when I initialize a mock with #RunWith(MockitoJUnitRunner.class), I get an error when I call a method from the mocked class. However, if I initialize using #BeforeEach, it works fine. to be more specific:
#RunWith(MockitoJUnitRunner.class)
class Test {
#Mock
Bean mockBean;
#Test
void testGet() {
Mockito.when(mockBean.method()).thenReturn(2);
assertEquals(2, mockBean.method());
}
The above causes a NullPointException error on the line Mockito.when(mockBean.method()).thenReturn(2);
H**owever, if I do the below:
class Test {
#Mock
Bean mockBean;
#BeforeEach
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
void testGet() {
Mockito.when(mockBean.method()).thenReturn(2);
assertEquals(2, mockBean.method());
}
the test runs just fine. I was under the impression that the two should work the same. I'd appreciate it if anyone could tell me what I am doing wrong or misunderstanding.
Related
I am completely stumped. I am new to Spring Batch testing and I have found countless examples that have left me confused.
I'm trying to test a Spring Batch decider. This decider checks to see if certain JSON files exist before continuing.
To begin, I have a BatchConfiguration file marked with #Configuration in my Spring Batch project.
In the BatchConfiguration, I have a ImportJsonSettings bean which loads its properties from settings in the application.properties file.
#ConfigurationProperties(prefix="jsonfile")
#Bean
public ImportJSONSettings importJSONSettings(){
return new ImportJSONSettings();
}
When running the Spring Batch application, this works perfectly.
Next, here are the basics of the JsonFilesExistDecider , which Autowires a FileRetriever object...
public class JsonFilesExistDecider implements JobExecutionDecider {
#Autowired
FileRetriever fileRetriever;
#Override
public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) { ... }
The FileRetriever object itself Autowires the ImportJSONSettings object.
Here is the FileRetriever...
#Component("fileRetriever")
public class FileRetriever {
#Autowired
private ImportJSONSettings importJSONSettings;
private File fieldsFile = null;
public File getFieldsJsonFile(){
if(this.fieldsFile == null) {
this.fieldsFile = new File(this.importJSONSettings.getFieldsFile());
}
return this.fieldsFile;
}
}
Now for the test file. I am using Mockito for testing.
public class JsonFilesExistDeciderTest {
#Mock
FileRetriever fileRetriever;
#InjectMocks
JsonFilesExistDecider jsonFilesExistDecider;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testDecide() throws Exception {
when(fileRetriever.getFieldsJsonFile()).thenReturn(new File(getClass().getResource("/com/files/json/fields.json").getFile()));
// call decide()... then Assert...
}
}
PROBLEM... The ImportJSONSettings object that is #Autowired in the FileRetriever object is always NULL.
When calling the testDecide() method, I get a NPE since calling the getFieldsJsonFile() in FileRetriever, the ImportJSONSettings bean does not exist.
How does the ImportJSONSettings bean get properly created in the FileRetriever object so it can be used??
I have tried adding the following to my test class, but it does not help.
#Mock
ImportJSONSettings importJSONSettings;
Do I need to create it independently? How does it get injected into the FileRetriever?
Any help would be appreciated.
Try changing the #Before annotation on the setup() method to #BeforeEach like so:
#BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
}
This could also be a dependency issue. Make sure you have a recent version of io.micrometer:micrometer-core. Would you be able to share your test dependencies?
If you have the above setup correctly, you shouldn't have to worry about whether or not ImportJSONSettings is null or not as long as you have getFieldsJsonFile() stubbed correctly.
#RunWith(SpringRunner.class)
#WebAppConfiguration
Class Test{
#Autowired
public SomeBean someBean;
#Test
public void testAccountPage2() throws Exception {
SomeBean someBean = mock(SomeBean.class);
given(someBean.getAccount(anyString())).willReturn(getCustomer());
}
Here someBean.getAccount(anyString()) is not mocking, which is calling the actual method of that bean impl. It seems it's taking the Autowired object not the mocked one.
Could anyone help me to mock beans in method level? those beans are also autowired in the same class or superclass.
Thanks
To replace a bean in the Spring container by a Mockito mock, use #MockBean.
import org.springframework.boot.test.mock.mockito.MockBean; // import to add
#RunWith(SpringRunner.class)
#WebAppConfiguration
Class Test{
#MockBean
public SomeBean someBean;
#Test
public void testAccountPage2() throws Exception {
given(someBean.getAccount(anyString())).willReturn(getCustomer());
}
}
To understand the difference between Mockito and MockBean from Spring Boot, you can refer to this question.
You need to inject the mock in order to have it working instead of autowiring
//if you are just testing bean/services normally you do not need the whole application context
#RunWith(MockitoJUnitRunner.class)
public class UnitTestExample {
#InjectMocks
private SomeBean someBean = new SomeBean();
#Test
public void sampleTest() throws Exception {
//GIVEN
given(
someBean.getAccount(
//you should add the proper expected parameter
any()
)).willReturn(
//you should add the proper answer, let's assume it is an Account class
new Customer()
);
//DO
//TODO invoke the service/method that use the getAccount of SomeBean
Account result = someBean.getAccount("");
//VERIFY
assertThat(result).isNotNull();
//...add your meaningful checks
}
}
Versions:
Java: 1.8
Spring Boot: 1.5.4.RELEASE
Application Main:
#SpringBootApplication
public class SpringbootMockitoApplication implements CommandLineRunner {
#Autowired
MyCoolService myCoolService;
public static void main(String[] args) {
SpringApplication.run(SpringbootMockitoApplication.class, args);
}
#Override
public void run(String... strings) throws Exception {
System.out.println(myCoolService.talkToMe());
}
}
My Service Interface:
public interface MyCoolService {
public String talkToMe();
}
My Service Implementation:
#Service
public class MyCoolServiceImpl implements MyCoolService {
#Override
public String talkToMe() {
return "Epic Win";
}
}
My Test class:
#RunWith(SpringRunner.class)
#SpringBootTest
public class SpringbootMockitoApplicationTests {
#MockBean
private MyCoolService myCoolService;
#Test
public void test() {
when(myCoolService.talkToMe()).thenReturn("I am greater than epic");
}
}
Expected Output: I am greater than epic
Actual Output: null
I simply want to replace the bean instance in the context with a mock that will return "I am greater than epic". Have I misconfigured something here?
The run method of any CommandLineRunners is called as part of SpringApplication being run. This happens when the test framework is bootstrapping the application context for your tests. Crucially, this is before your test method has set any expectations on your MyCoolService mock. As a result the mock returns null when talkToMe() is called.
Something may have been lost in reducing your problem to a simple example, but I don't think I'd use an integration test here. Instead, I'd unit test your CommandLineRunner with a mock service. To so so, I'd recommend moving to constructor injection so that you can pass the mock directly into the service's constructor.
Using Spring boot starter test for testing my application but I am using third party library. Lets suppose we have a class TRequest and it has some constructor and I want to mock and stub that constructor to return the result.
#SpringBootTest
#RunWith(SpringRunner.class)
#PrepareForEverythingForTest
public class TestClass {
#MockBean
TRequest trequest ;
#Before
public void setUp() throws Exception {
PowerMockito.whenNew(TRequest.class).withAnyArguments().thenReturn(trequest);
}
}
Now when I am trying to create the constructor using new, it is not returning the correct stubbed result.
TRequest trequest1 = new TRequest("apiKey","secretKey") ;
trequest.equals(trequest1) ; // false but I want it to be true
Have used a jackson third party lib to test with. - getting ClassLoader exceptions because of PowerMock though.
#SpringBootTest
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringRunner.class)
public class TestPowerMockito {
#MockBean
ObjectMapper object;
#Before
public void init() throws Exception {
PowerMockito.whenNew(ObjectMapper.class).withAnyArguments().thenReturn(object);
}
#Test
public void test() {
assertEquals(object, new ObjectMapper());
}
}
I am trying to run JUnit test for my controller which has 2 autowired fields .
While running it, I am getting a null pointer exception on this object, hence failing to execute. I am new to this Spring JUnit test.
I tried almost all combination that was posted earlier related to JUNIT. None of them works.
helper and model are two autowired fields used in my test. My test goes to the controller and fails with null pointer exception. The object helper exist in my Test class, but it is null in the controller.
Can anyone help me in finding a solution this. Below is my code
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "xml/applicationContext.xml"})
#WebAppConfiguration
public class XYZTest {
WebApplicationContext webApplicationContext;
#Autowired
#Qualifier("helper")
Helper helper;
#Autowired
#Qualifier("model")
Model myModel;
DispatcherPortlet dispatcherPortlet;
#Test
public void testInitialize() throws Exception {
DispatcherPortlet portlet = new DispatcherPortlet() {
protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) throws BeansException {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(ExplanationOfBenefitController.class));
wac.refresh();
return wac;
}
};
portlet.init(new MockPortletConfig());
MockRenderRequest request = new MockRenderRequest(PortletMode.VIEW);
MockRenderResponse response = new MockRenderResponse();
//System.out.println("helper:"+helper);
portlet.render(request, response);
assertEquals("tableJSP", response.getContentAsString());
}
}
Can I use the autowired field created in JUNIT test class, in controller?