passing properties field using #value annotation to mocked method is null - java

I am unable to pass the field by reading from application-test.properties file from test to the mocked method.
#RunWith(SpringRunner.class)
#TestPropertySource("classpath:application-test.properties")
public class ReportImplTest {
#Mock
private Dependencies dependencies;
#InjectMocks
private ReportImplTest underTest;
#Test
public void testgetReports() {
List<String> reps= underTest.getReports(anyString());
}
}
Here is the actual class of the mocked method
#Component
public class ReportImpl {
#Value("${REP_PROPNAME}")
String reppropname;
public List<String> getReports(String rep){
return staticUtilityclass.process(staticUtilityclass.transform(reppropname,"Reports"));
}
}
reppropname is coming as null in the getReports method. Test is executing in test context wheres the ReportImpl class will be in application context. Is there a way to get the value of the reppropname.
I tried used #ContextConfiguration (#ContextConfiguration(classes={ApplicaitonBootStarter.class)}
it is working , but it loads all the beans and dependencies.
Any other way to get the reppropname?

The reason why the value is not injected here is that you don't provide the configuration to your test class. Spring just doesn't know how to build your bean.
So, as you mentioned you have to annotate the test class with #ContextConfiguration. If you don't want to build the entire context with all the beans, you can provide create a test configuration and provide there only the needed beans.
#Configuration //can be as well annotated with #TestConfiguration
#ComponentScan("package.to.scan")
public class TestConfiguration {
}
And now provide this class to your test
#RunWith(SpringRunner.class)
#TestPropertySource("classpath:application-test.properties")
#ContextConfiguration(classes = TestConfiguration.class)
public class ReportImplTest {
........
}
But there is one more thing. Assuming that you have a #Before method that performs MockitAnnotations.initMocks(this);, you still have your object-under-test declared only with #InjectMocks. What does it mean? It means that if you don't initialize this object by yourself, mockito will take care of it and will initialize with using the available constructor, and in this case, spring won't inject the #Value annotated field. What you need to do, is to annotate you object-under-test with #Autowired so spring will initialize it before mockito will try to take care of it:
#InjectMocks
#Autowired
private ReportImplTest underTest;

Related

#InjectMocks inject #MockBean by Constructor and setter not working properly

I have try so many time by unsing #RunWith(SpringJUnit4ClassRunner.class)
I have tried to create a test case foe a class with getter and Constructor injection. When i user #MockBean for setter injection, #Mock for Constructor injection and also use #RunWith(SpringJUnit4ClassRunner.class) and MockitoAnnotations.initMocks(this); bean injection.
If i comment MockitoAnnotations.initMocks(this); constructor injection not working.
Now all beans are injected perfectly but #Mock beans(Contructor injected ) beans mocked mthods not working properly when its called.
#Component
Class A{
}
#Component
Class B {
}
#Component
Class c{
}
#Component
Class D{
#Atowired
A a;
B b;
C c;
#Autowired
public D(B b,C c){
b=b;
c=c;
}
}
My Test Class is
#RunWith(SpringJUnit4ClassRunner.class)
Class TestClass{
#MockBean
A mockA
#Mock
B mockB
#Mock
C mockC
#InjectMocks
D mockD
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);//Without this Constructor injection not working
when(mockA.getValue()).then("StringValA");
when(mockB.getValue()).then("StringValB");
when(mockC.getValue()).then("StringValC");
}
#Test
public void testMethod(){
mock.getAllValues();// It will call all injested bean method we are mocked in #before
}
}
The injections are working properly ,issue is belongs to mocked methods of beans which i use #Mock is not working properly means mockB.getValue() and mockC.getValue() retun null but mockA.getValue() return correctly when i test run.
If you are running a test with SpringJUnit4ClassRunner.class then you need to use #MockBean instead of #Mock.
Please refer to the spring boot documentation
Also, you need to use #Autowired instead of #InjectMocks.
#RunWith(SpringJUnit4ClassRunner.class)
Class TestClass{
#MockBean
A mockA
#MockBean
B mockB
#MockBean
C mockC
#Autowired
D mockD
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);//Without this Constructor injection not working
when(mockA.getValue()).then("StringValA");
when(mockB.getValue()).then("StringValB");
when(mockC.getValue()).then("StringValC");
}
#Test
public void testMethod(){
mock.getAllValues();// It will call all injested bean method we are mocked in #before
}
}
When you run the test with spring runner, you must specify what exactly would you like to load as beans (read, let spring know what exactly should be included into the application context).
Usually this can be done with #ContextConfiguration annotation.
I suspect that since you don't specify this annotation, spring doesn't really loads any of your components (A, B, C in the question, etc).
Now #MockBean basically allows "altering" the application context for test purposes. It does so by providing a mock instead of a real bean that should have been loaded in "regular" application context.
In this case, there is no point to call MockitoAnnotations.initMocks(this); Spring will inject the mocks by itself once everything is configured properly.
Solution :
#RunWith(SpringJUnit4ClassRunner.class)
Class TestClass{
#MockBean
A mockA
#MockBean
B mockB
#MockBean
C mockC
#Autowired
D mockD
#Before
public void setUp() {
mockD = new D(mockA,mockB);
MockitoAnnotations.initMocks(this);
when(mockA.getValue()).then("StringValA");
when(mockB.getValue()).then("StringValB");
when(mockC.getValue()).then("StringValC");
}
#Test
public void testMethod(){
mock.getAllValues();// It will call all injested bean method we are mocked in #before
}
}
Normal bean initialize methods like SpringJUnit4ClassRunner or MockitoAnnotations.initMocks(this); handling only one type injection at a time. Either constructor or Auto wired injection.
#RunWith(SpringJUnit4ClassRunner.class)
means public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner. SpringJUnit4ClassRunner is a custom extension of JUnit's. It will initialize mock the #MockeBean and #bean anotted beans at the intial time of test run.Alsoi runnig the bean injection also.
MockitoAnnotations.initMocks(this) method has to called to initialize annotated fields. In above example, initMocks() is called in #Before (JUnit4) method of test's base class. For JUnit3 initMocks() can go to setup() method of a base class.
So that in above question you have used the SpringJUnit4ClassRunner and MockitoAnnotations.initMocks(this); it will create two mock bean references for which ever you use the #Mock. Also in above code flow.
1.At the beginning the SpringJUnit4ClassRunner run it will create bean reference for #Mock and #MockBean annotated attributes.after that it will create injected bean at tjis time only happens the constructor injection
2.Run #Before and Run MockitoAnnotations.initMocks(this); it will create another mock references for #Mock annotated attributes and replaced direct reference only. and Auto wired injection run at this time.
After running the MockitoAnnotations.initMocks(this); you will see the allk beans are initialized and injected well. But beans which are injected thruogh constructor those beans are not correct reference these are referring old bean reference which are created by SpringJUnit4ClassRunner.
If you want to achieve the constructor and Auto wired injection for a single bean you must to use manual bean injected for the constructor injection. you can refer here

Null pointer on an autowired bean which is not mocked by mockito

I have a service class that I need to unit test. The service has a upload method which in turn calls other services(autowired beans) that updates the database. I need to mock some of these services and some to execute as it is.
#Service
public class UploadServiceImpl implements UploadService{
#Autowired
private ServiceA serviceA;
#Autowired
private ServiceB serviceB;
public void upload(){
serviceA.execute();
serviceB.execute():
//code...
}
In the above example I need to mock ServiceA, but i would like ServiceB to run as is and perform it's function.
My Junit test looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes=Swagger2SpringBoot.class)
public class UploadServiceTest {
#Mock
private ServiceA serviceA;
#InjectMocks
private UploadServiceImpl uploadService;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testUpload(){
uploadService.upload();
}
When I execute this I get NPE at serviceB.execute(); in UploadServiceImpl.
What could be the problem?
Note: I am not specifying the behavior of the mocked object because I don't really care and also default behavior of mocked objects are to do nothing.
Thanks!
Usually when unit testing you want to mock all external dependencies of a class. That way the unit test can remain independent and focused on the class under test.
Nevertheless, if you want to mix Spring autowiring with Mockito mocks, an easy solution is to annotate with both #InjectMocks and #Autowired:
#InjectMocks
#Autowired
private UploadServiceImpl uploadService;
The net effect of this is that first Spring will autowire the bean, then Mockito will immediately overwrite the mocked dependencies with the available mocks.
The issue you are facing is due to the use of #InjectMocks annotation.#InjectMocks marks a field on which injection should be performed. Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection – in this order. If any of the given injection strategy fail, then Mockito won’t report failure.
So in your case when trying to inject mocks only one mock bean is present and the other bean ServiceA is not getting injected.To solve this issue :
You can try not using #InjectMocks at all instead pass a mock object for the method that you want to mock while pass rest of the autowired objects into the constructor.Example :
Here to test i am passing one mock object and one autowired object.
#RunWith(MockitoJUnitRunner.class)
public class SampleTestServiceImplTest {
#Mock
private SampleClient sampleClient;
#Autowired
private BackendService backendService ;
private BackendServiceImpl backendServiceimpl;
#Before
void setUp() {
backendServiceimpl = new BackendServiceImpl(sampleClient, backendService);
}
Or another way you can make this work is by using #Autowired annotation along with the #InjectMocks.#Autowired #InjectMocks are used together and what it will do is inject the mocked class and Autowired annotation adds any other dependency which the class might have.
Answer referred from : https://medium.com/#vatsalsinghal/autowired-and-injectmocks-in-tandem-a424517fdd29
In my opinion, we are writing unit test cases and we should not initialize the spring context in order to test a piece of code.
So,
I used Mockito to mock the Autowired beans in my main target test class and injected those mock beans in my main test class Object
maybe sounds confusing, see the following example 💥
Dependencies I used
testImplementation("org.mockito:mockito-core:2.28.2")
testImplementation("org.mockito:mockito-inline:2.13.0")
testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
testImplementation("org.mockito:mockito-junit-jupiter:4.0.0")
My main class is Maths and Calculator bean is autowired
class Maths{
#Autowired Calculator cal;
.........
.........
public void randomAddMethod(){
cal.addTwoNumbers(1,2); // will return 3;
}
}
Test class
#ExtendWith(MockitoExtension.class)
class MathsTest{
#Mock(answer = Answers.RETURNS_DEEP_STUBS) Calculator cal;
#InjectMocks Maths maths = new Maths();
#Test testMethodToCheckCalObjectIsNotNull(){
maths.randomAddMethod();
}
}
Now cal will not be null in Maths class and will work as expected
Add
#Mock
private ServiceB serviceB;
to create injectable mock of missing service just like you did with service A.
In my case, beside using combination of #InjectMocks and #Autowired, I also had to provide setter for the mocked object in the tested class (setter for ServiceA in UploadServiceImpl in the original example). Without that the real method of ServiceA was called.
Another way is to define an autowired constructor so that you can test the services properly.
#Service
public class UploadServiceImpl implements UploadService{
private ServiceA serviceA;
private ServiceB serviceB;
#Autowired
public UploadServiceImpl(ServiceA serviceA, ServiceB serviceB) {
this.serviceA = serviceA;
this.serviceB = serviceB;
}
public void upload(){
serviceA.execute();
serviceB.execute():
//code...
}
I couldn't make it work without using ReflectionTestUtils. Setting the constructor is one option if it's viable for you.

When running test class, properties can't be read properly from .properties file by using #Value annotation, in Spring Maven project

//Update
After viewing helpful comments, I realize the problem should then be, how to unit test method using values read from properties by #Value .
//
I am working on this issue for days, I am writing unit test for a serviceClass.The serviceClass is like below :
import ...
#Component
public class ServiceClass implements ServiceInterface {
#Value("${data.layer.url}")
private String dataLayerUrl;
#Autowired
private RestTemplate restTemplate
public void dummy(){
restTemplate.postForObject(dataLayerUrl + "/" + ... , ...);
}
}
And CONFIG_DIR is already defined in application configuration file.
I have a SomeConfig class defining beans as below. (...src/main/java/com.app/configuration/SomeConfig)
#Configuration
#ComponentScan(basePackages = {"..."})
#PropertySource(value = "file:${CONFIG_DIR}/app.properties")
public class SomeConfig{
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
...
return restTemplate;
}
}
My test class is as below:
Import ...
#Profile("test")
public class ServiceClassTest extends AbstractTest {
#Value("${data.layer.url}")
private String dataLayerUrl;
#InjectMocks
private ServiceClass ServiceClass;
#Mock
RestTemplate restTemplate;
#Before
public void initializeMockito() {
MockitoAnnotations.initMocks(this);
}
#Test
public void dummyTest(){
when(restTemplate.postForObject(dataLayerUrl + "/" + ..., ...)).thenReturn(...);
serviceClass.dummy();
assertEquals(...);
verify(restTemplate).postForObject(...);
}
}
And then my AbstractTest as below :
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("test")
#SpringApplicationConfiguration(classes = Application.class)
#ContextConfiguration(classes = {TestConfiguration.class})
#ComponentScan(basePackages = ...)
public abstract class AbstractTest {
protected Logger logger = LoggerFactory.getLogger(this.getClass());
}
And I also have .../src/test/resources/application-test.properties defined as below
#Datalayer properties
data.layer.url=http://camel-dev-01.xxx.com:5001
This is the same as defined in application.properties(which locates outside of project in CONFIG_DIR.
The logic of testing is just to make sure when you call dummy method of serviceClass, the postForObject method of restTemplate is called exactly once.
But when doing it this way, I am facing with 2 problems.
when I run test class in debug mode, I found
in ServiceClassTest. dataLayerUrl = "$data.layer.url"
in ServiceClass. dataLayerUrl = null
I researched around and be able to solve problem one by following this link
https://gist.github.com/danlangford/3418696
But this is not an ideal way to do this, since by default spring should be able to read properties from application-test.properties.
And I never figured out what caused the second issue and how to solve it.
I think this would be a common issue when writing unit test on class which read properties from .properties file using $Value annotation. Any comments or suggestions would be very much appreciated.
The key point hear as said M. Deinum is that you use a mix of Spring bean and Mock Object that in this case aren't Spring bean and for this reason can't benefit of the feature of Spring Container such as the injection of the properties.
In particular you should use the spring test abstraction as a "integration test" istruments. With this words I intended that you should use this abstraction, for test the correct configuration, behavior and so on fo your bean in the spring contex. However if you use Stub or mock object you actually exit, of a smal part probably, by the management of spring and the your test don't make sense. Using stub or mock the your test become a Unit test in sense that it will be a test the your bean and functionality in isolation infact you have mock or stub the dependency of your object.
I hope that this reflection could be help you
I am glad to know there is no way to read values from properties by #Value inside a mock obj.
But still my problem is that I want to unit test my dummy method in ServiceClass. Put it another way, as long as I could unit test this method, I don't care whether #Value works or not.
Here is my solution of test method
#Profile("test")
public class ServiceClassTest extends AbstractTest {
#Value("${data.layer.url}")
private String dataLayerUrl;
#InjectMocks
private ServiceClass ServiceClass;
#Mock
RestTemplate restTemplate;
#Before
public void initializeMockito() {
MockitoAnnotations.initMocks(this);
}
#Test
public void dummyTest(){
when(restTemplate.postForObject(anyString() , eq(), eq() )).thenReturn(...);
serviceClass.dummy();
assertEquals(...);
verify(restTemplate).postForObject(anyString(), eq(), eq());
}
By using anyString, I don't rely on what value is read from properties, since I only want to test whether dummy method call restTemplate's postForObject method properly.
You need to add PropertySourcesPlaceholderConfigurer to your test configuration in order to populate properties annotated with #Value annotation. Spring Boot adds it to configuration, but since your test is running without Spring Boot you have to declare it. For more details seehere .
in place of #InjectMocks you can write #Autowired and I thing you can use both annotation like that
Case 1
#InjectMocks
private ServiceClass ServiceClass;
case 2
#Autowired
#InjectMocks
private ServiceClass ServiceClass;
I have same issue but after discussion my senior I have find above like solutions

Tests injecting beans with #Autowired annotations

I want to write unit test using Junit and Mockito, in this case I don't want to write integration tests. The method that I want to test uses variables that are injected via Spring using the #Value or #Autowired annotations. How can I populate the injected variables so that when I run a test they are not null. Before days of annotations I would have created mocked classes of the variables and set them via setter methods.
I'm writing unit tests so I would prefer not to use #RunWith(SpringJUnit4ClassRunner.class).
You can use the MockitoJUnitRunner.
class SystemUnderTest {
#Autowired
private Dependency dep;
// ...
}
#RunWith(MockitoJUnitRunner.class)
public class YourTest {
#Mock
private Dependency mockDependency;
#InjectMocks
private SystemUnderTest testee;
#Test
public void testSystem() {
// at this point testee is already injected with mockDependency
}
}

Injecting Mockito Mock objects using Spring JavaConfig and #Autowired

I'm trying to replace an #Autowired object with a Mockito mock object. The usual way of doing this was with xml using Springockito:
<mockito:mock id="SomeMock" class="com.package.MockInterface" />
Currently I'm trying to move over to using Spring's JavaConfig to do the job. All of a sudden the Java expressions are a whole lot more verbose than xml:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class MyTestClass {
#Configuration
static class Config {
#Bean
public MockInterface somethingSpecial() {
return Mockito.mock(MockInterface.class);
}
}
#Autowired MockInterface mockObj;
// test code
}
I discovered a library called Springockito-annotations, which allows you to do the following:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=SpringockitoContextLoader.class)
public class MyTestClass {
#Autowired #ReplaceWithMock MockInterface mockObj;
// test code
}
Clearly, a whole lot prettier :) The only problem is that this context loader doesn't allow me to use #Configuration and JavaConfig for other beans (if I do, Spring complains that there are no candidates that match those autowired fields).
Do you guys know of a way to get Spring's JavaConfig and Springockito-annotations to play nice? Alternatively, is there another shorthand for creating mocks?
As a nice bonus, using Springockito and xml config, I was able to mock out concrete classes without providing autowiring candidates to its dependencies (if it had any). Is this not possible without xml?
Moving away from the now unmaintained (as of this writing) Spingockito-annotations and to Mockito, we have a way of doing this very simply:
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration
public class MyTestClass {
#Mock MockInterface mockObj;
// test code
}
If you're using a real object, but would like to mock a dependency within it, for instance testing a service layer with DAO:
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration
public class MyTestClass {
#InjectMocks RealService;
#Mock MockDAO mockDAO;
// test code
}
Finally, this can also be applied to Spring-boot, but using annotation initialization within setUp() until multiple class runners are supported:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MyMainSpringBootClass.class)
public class MyTestClass {
#InjectMocks RealService;
#Mock MockDAO mockDAO;
#Before
public final void setUp() throws Exception{
MockitoAnnotations.initMocks(this);
}
// test code
}
Outdated and deprecated!
Read about mocking and spying in Spring Boot 1.4
Please read also #ethesx answer,
Springockito is unmaintaned
Old answer
This is possible now to mock Spring application without any XML file with Springockito-annotations.. This solution works also with Spring Boot.
import static org.mockito.BDDMockito.*;
import org.kubek2k.springockito.annotations.*;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = Application.class,
loader = SpringockitoAnnotatedContextLoader.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class MainControllerTest {
#Autowired
MainController mainController;
#Autowired
#ReplaceWithMock
FooService fooService;
#Test
public void shouldGetBar() {
//given
given(fooService.result("foo")).willReturn("bar");
//when
Bar bar build = fooService.getBar("foo");
//then
assertThat(bar).isNotNull();
}
}
Dependencies: org.kubek2k:springockito-annotations:1.0.9
It appears that SpringockitoContextLoader extends GenericXmlContextLoader which is described as:
Concrete implementation of AbstractGenericContextLoader that reads bean definitions from XML resources.
So you are limited to xml bean definitions at the moment.
You could write your own context loader, taking relevant parts from the SpringockitoContextLoader class. Take a look here to get started, perhaps you could extend AnnotationConfigContextLoader for example?

Categories