I have an object reads configuration properties like this:
#ApplicationScoped
public class Configuration {
#Inject
#Config(value = "endpoint.base", defaultValue = "http://localhost:52885/consumers")
private String base;
public String getBase() { return base; }
}
this object is injected to a service object like this:
public class LoyaltyService {
final Sender sender;
final Configuration config;
#Inject
public LoyaltyService(Sender sender, Configuration config) {
this.sender = sender;
this.config = config;
}
}
I am now testing this service object with Mockito. I want to mock the Sender object, but I don't want to mock the configuration, or at least I just want to use the default value defined inside the object.
How can I do that in a Test object?
For example, I tried the following:
public class LoyaltyServiceTest {
#Mock
private Sender sender;
#Inject
private Configuration config;
private LoyaltyService target;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
when (sender.post(anyString(), anyString())).thenReturn("Post Success");
target =new LoyaltyService(sender, config);
}
}
It doesn't seem CDI will register the Config object at all. How does this work? Thanks!
It doesn't seem CDI will register the Config object at all.
The CDI beans are not initialised when running the test, only the mocked objects are.
MockitoAnnotations.initMocks only initializes
objects annotated with Mockito annotations for given testClass: #Mock, #Spy, #Captor, #InjectMocks.
You need to use a CDI test framework like cdi-unit or Pax Exam in your test class to create the non-mocked beans for you.
Related
I'm trying to inject a mock for a unit test but I keep getting a null point exception.
The class I'm trying to test is below, the null pointer seems to be with the ParameterFacade.
When I run the test it doesn't seem to be injecting the mock as the ParameterFacade is null.
#Service
public class PostUnderwriterTransactionProcessProvider extends AbstractProcessProvider<PostUnderwriterTransactionInput> {
#Autowired
private ParameterFacade parameterService;
#Override
public Page startProcess(PostUnderwriterTransactionInput processInput) {
final PostUnderwriterTransactionContext context = new PostUnderwriterTransactionContext(processInput.getPolicy(),
setupStrataContextModel(POST_TRANSACTIONS),
processInput.getTransactionsTypes(),
processInput.getParameterSelectionCriteria(),
parameterService.shouldApplyCommissionFromPolicy());
context.setPostingFromInput(processInput.getAccount().getBalance(),
processInput.getAccount().getID(),
getBranch(),
processInput.getPolicy(),
processInput.getProcess(),
null);
return new AdhocTransactionPostingPage(new TransactionPostingContextModel(context));
}
}
The test is
#RunWith(MockitoJUnitRunner.class)
public class PostUnderwriterTransactionProcessProviderTest extends WicketTestCase {
#ClassRule
public static MetadataServiceRule metadataServiceRule = new MetadataServiceRule();
#Mock
private ParameterFacade mockParameterService;
#InjectMocks
private PostUnderwriterTransactionProcessProvider testSubject;
#Before
public void setup() {
tester.putBean(mockConversationScopeManager);
testSubject = new PostUnderwriterTransactionProcessProvider();
policy = PolicyTestDataBuilder.aPolicy().build();
account = createAccount();
testSubject.setUserInfoProvider(MockUserInfoPartyProvider.getMockUserInfoProvider());
testSubject.setSystemPartyFacade(MockUserInfoPartyProvider.getMockSystemPartyFacade());
testSubject.setCodeModelFacade(codeModelFacade);
}
#Test
public void startProcessShouldCreateAdhocTransactionPostingPage() {
// Given
when(mockParameterService.shouldApplyCommissionFromPolicy()).thenReturn(true);
final ParameterSelectionCriteriaModel pscm = new ParameterSelectionCriteriaModel();
final List<TransactionTypeModel> transactions = createTransactionsTypes();
final PostUnderwriterTransactionInput input = new PostUnderwriterTransactionInput(policy, account, pscm, transactions);
// When
final Page page = testSubject.startProcess(input);
// Then
assertThat(page, instanceOf(AdhocTransactionPostingPage.class));
assertThat("Page Default Model is: ", page.getDefaultModelObject(), instanceOf(PostUnderwriterTransactionContext.class));
assertPageContextValues(page);
}
}
1. ParameterFacade is a spring container managed bean (as it is annotated with #Service and other spring annotations like #Autowired).
2. #RunWith is configured to use MockitoJUnitRunner which cannot instantiate spring managed container beans
Hence, in order to handle bean lifecycle in unit tests you'll need to
1. Use #RunWith(SpringJUnit4ClassRunner.class)
2. Annotate PostUnderwriterTransactionProcessProvider with #Autowired.
3. Change #Mock to #MockBean on ParameterFacade (org.springframework.boot.test.mock.mockito.MockBean)
Take a look at you following code, let's see what each line does -
#Mock
private ParameterFacade mockParameterService; //1
#InjectMocks
private PostUnderwriterTransactionProcessProvider testSubject; // 2
#Before
public void setup() {
testSubject = new PostUnderwriterTransactionProcessProvider(); //3
}
Line 1 uses spring framework's #Mock annotation. This tells spring to mock an object of type ParameterFacade, create a mocked instance and hold it in the mockParameterService variable
Line 2 uses the #InjectMocks annotation, which tell spring to use the mocked object created in this test (which we created in line 1) and use it as a dependency in the variable testSubject when creating it. This will result in testSubject containing an instance of PostUnderwriterTransactionProcessProvider that has a dependency of a mocked type ParameterFacade injected to him
Line 3 creates a new instance of PostUnderwriterTransactionProcessProvider. this is pure java, no spring, no mocks, no dependencies. Simply create a new instance of that type the regular way java would do that. The instance that was created in 2 is replaced by this new plain instance and , in a way any assertion will override a previous value, which leaves the variable testSubject holding this object
The line
testSubject = new PostUnderwriterTransactionProcessProvider();
is overriding the instance created with
#InjectMocks
private PostUnderwriterTransactionProcessProvider testSubject;
Remove the manual initialization to let the framework behave as designed.
Otherwise, if you want to be able to manually inject the dependency then consider refactoring the class to follow Explicit Dependency Principle
#Service
public class PostUnderwriterTransactionProcessProvider
extends AbstractProcessProvider<PostUnderwriterTransactionInput> {
private final ParameterFacade parameterService;
#Autowired
public PostUnderwriterTransactionProcessProvider(ParameterFacade parameterService) {
this.parameterService = parameterService;
}
//...omitted for brevity
}
This can allow more flexibility when creating the subject
#RunWith(MockitoJUnitRunner.class)
public class PostUnderwriterTransactionProcessProviderTest extends WicketTestCase {
#ClassRule
public static MetadataServiceRule metadataServiceRule = new MetadataServiceRule();
#Mock
private ParameterFacade mockParameterService;
private PostUnderwriterTransactionProcessProvider testSubject;
#Before
public void setup() {
tester.putBean(mockConversationScopeManager);
testSubject = new PostUnderwriterTransactionProcessProvider(mockParameterService);
//...omitted for brevity
I'm trying to write a test in a Spring-Boot project. My problem is that I can't use my service that includes a constructor injection.
Depending on what I try I get errors like java.lang.IllegalStateException: Failed to load ApplicationContexts or NullPointerExceptions.
My first try was to change the constructor injection in my service to a field injection. But after reading this post I decided to change it back to the previous way.
Then I searched for examples but couldn't find something that was helpful.
Following are the relevant code snippets. If more code is needed I would provide it.
The service class with the constructor injection:
PlayerServiceImpl.java
#Service
public class PlayerServiceImpl implements PlayerService {
private PlayerRepository playerRepository;
private CompanyService companyService;
private CompanyResourceService companyResourceService;
#Autowired
public PlayerServiceImpl(PlayerRepository thePlayerRepository, CompanyService theCompanyService,
CompanyResourceService theCompanyResourceService) {
this.playerRepository = thePlayerRepository;
this.companyService = theCompanyService;
this.companyResourceService = theCompanyResourceService;
}
...
}
The test class im trying to create:
PlayerServiceImplIntegrationTest.java
#RunWith(SpringRunner.class)
#SpringBootTest
public class PlayerServiceImplIntegrationTest {
#TestConfiguration
static class PlayerServiceImplTestContextConfiguration {
private PlayerRepository playerRepository;
private CompanyService companyService;
private CompanyResourceService companyResourceService;
#Bean
public PlayerService playerService() {
return new PlayerServiceImpl(playerRepository, companyService, companyResourceService);
}
}
#Autowired
private PlayerService playerService;
#MockBean
private PlayerRepository playerRepository;
#Before
public void setUp() {
Player max = new Player("MaxMustang", "test123", "MaxMustang",
"max.mustang#test.com", new Date(System.currentTimeMillis()), 1, 0,
new BigDecimal("0.00"), new BigDecimal("0.00"), 0, 0);
Mockito.when(playerRepository.findByUserName(max.getUserName()))
.thenReturn(max);
}
#Test
public void whenFindById_thenReturnPlayer() {
String userName = "MaxMustang";
Player found = playerService.findByUserName(userName);
assertThat(found.getUserName()).isEqualTo(userName);
}
}
In my test, I'm trying to create a player object and receive it. It's just my first test in Spring Boot. And my main goal was to just get the test running.
And the original test is from Baeldung from "5. Mocking with #MockBean". But while experimenting around, I added or changed a few things.
If I missed a post pointing at the same problem I would be glad to be informed about that.
Also, I would appreciate it if someone can tell me if the arguments in the constructor of my service are too much or still in an "ok" range.
You have to make the configuration bean primary and also use constructor injection on that method:
#TestConfiguration
static class PlayerServiceImplTestContextConfiguration {
#Bean
#Primary
public PlayerService playerService(PlayerRepository playerRepository,
CompanyService companyService, CompanyResourceService companyResourceService) {
return new PlayerServiceImpl(playerRepository, companyService, companyResourceService);
}
}
Without primary you will have two beans of same type floating around and you dont use #Qualifier here. Also you cannot #Autowire beans in a configuration class thats why you need to use constructor injection.
Here I am trying to mock autowire fields ServiceHelper of Service class TestServiceImpl , I am not able to call method through mock object of ServiceHelper class.
This is my class files:
#Service
public class TestServiceImpl implements TestService {
#Autowired
private TestDAO testDAO;
#Autowired
private ServiceHelper serviceHelper;
#Override
public ResultsModel getResults(Map<String, Object> map) throws WebServiceException_Exception {
return serviceHelper.getResults(map);
}
2nd Class:
#Repository
public class ServiceHelper {
private static Logger logger = Logger.getLogger(ServiceHelper.class.getName());
#Autowired
ResponseHeader responseHeader;
public void setResponseHeader(ResponseHeader responseHeader) {
this.responseHeader = responseHeader;
}
public ResultsModel getResults(Map<String, Object> map) throws WebServiceException_Exception {
....
}
And Test class:
#RunWith(MockitoJUnitRunner.class)
public class MockitoTester {
#InjectMocks
private TestServiceImpl serviceImpl = new TestServiceImpl();
#Mock
private TestDAO testDAO;
#Mock
private ServiceHelper sHelper;
#Before
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
#Test
public void testResult() throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("TestId", "test123");
map.put("lang", "en");
map.put("cntry", "USA");
ResultsModel results = new ResultsModel();
when(sHelper.getResults(map)).thenReturn(results);
results = serviceImpl.getResults(map);
Assert.assertEquals(results.getStatus(), "Success");
}
Here in my test class:
results = serviceImpl.getResults(map);
It goes to TestServiceImpl class to method :
public ResultsModel getResults(Map<String, Object> map) throws webServiceException_Exception {
return serviceHelper.getResults(map);
}
but at point :
serviceHelper.getResults(map);
it is not going inside serviceHelper.getResults(map) and return all values as Null.
Please suggest where I need to do changes.
You have three choices here:
Do actual Spring autowiring in your tests
Use injection methods that can legitimately be performed by your tests (constructor parameters, public setters, public fields - in order of preference)
Use reflection to inject your mocks
Option 1 is really integration testing -- you can annotate your test class with #RunWith(SpringRunner.class) and use more Spring annotations to control dependency injection. It's too big a subject to cover in a SO answer, but there are plenty of examples if you Google for "spring integration test mockito".
But for unit testing, I think it's better not to involve Spring. A good Spring bean doesn't need Spring to function. Option 2 just says, write your class so that unit tests (and anything else) can inject the dependency (be it a mock, or anything else) through normal Java means.
Constructor injection is cleanest in my opinion:
private final ServiceHelper serviceHelper; // note: not annotated
#Autowired
public TestService(ServiceHelper serviceHelper) {
this.serviceHelper = serviceHelper;
}
But you can also do this with a public void setServiceHelper(ServiceHelper helper) -- this is less good because the field can't be final.
Or by making the field public -- I assume you know the reasons this is bad.
If you're determined to have a private field that's not set by a public constructor or setter, you could use Spring's ReflectionUtils.setField() from within your test:
#Mock
private ServiceHelper serviceHelper;
private TestService service;
#Before
public void configureService() {
service = new TestService();
Field field = ReflectionUtils.findField(TestService.class, "serviceHelper");
ReflectionUtils.setField(field, service, serviceHelper);
}
(Or, equally, use JDK's reflection classes directly, or reflection utils from elsewhere)
This is explicitly using reflection to subvert the access rules you've coded into the class. I thoroughly recommend option 2.
I think the issue may be that you are stubbing your method to return the same object which you then assign the result of the method under test. i.e. (the results object here):
ResultsModel results = new ResultsModel();
when(sHelper.getResults(map)).thenReturn(results);
results = serviceImpl.getResults(map);
This will probably cause some sort of cyclic confusion when it tries to stub the method in Mockito, and it certainly won't make your assertation pass:
Assert.assertEquals(results.getStatus(), "Success");
Since the status on results is never set anywhere.
I think you need to make separate objects for your stubbing and your returned value from the method under test and make sure you set your stubbed one to have a status of "Success":
ResultsModel results = new ResultsModel();
results.setStatus("Success");
when(sHelper.getResults(map)).thenReturn(results);
ResultsModel returnedResults = serviceImpl.getResults(map);
Assert.assertEquals(returnedResults.getStatus(), "Success");
Try using constructor injection it'd be easier to mock the classes for testing... here's an example on how I would structure my classes to get you going. When you write your tests you now have to pass the Mocked object into the instance you're creating of these classes:
#Service
public class TestServiceImpl implements TestService {
private TestDao testDao;
private ServiceHelper serviceHelper;
#Autowired
public TestServiceImpl(TestDAO testDAO, ServiceHelper serviceHelper) {
this.testDAO = testDAO;
this.serviceHelper = serviceHelper;
}
}
#Repository
public class ServiceHelper {
private ResponseHeader responseHeader;
#Autowired
public ServiceHelper(ResponseHeader responseHeader) {
this.responseHeader = responseHeader
}
}
I have a Rest Controller in which I initialise a service like this :
class Config {
#Value(${"number.of.books"})
private final static String numberOfBooks;
}
class MyController {
private final Service myService = new ServiceImplementation(Config.numberOfBooks)
public ResponseEntity methodA() { ... }
}
The numberOfBooks field has a initialisation value but when it's passed in the ServiceImplementation constructor it comes null.
I'm thinking I'm missing something obvious over here.
What is the mistake and which would be the best practice to inject a value from a property file into a constructor?
I recommend you to directly inject numberOfBooks in your ServiceImplementation, as follows:
public class ServiceImplementation implements Service {
#Value("${number.of.books}")
private String numberOfBooks;
}
Otherwise use setter injection for static variables, as follows:
#Component
class Config {
public static String numberOfBooks;
#Value("${number.of.books}")
public void setNumberOfBooks(String numberOfBooks) {
numberOfBooks = numberOfBooks;
}
}
After studying a little I've found out that the dependency injection happens after the constructor has been called. This being said the approach used was to use Autowired on my services constructor.
class ServiceImplementation implements Service {
private final String numberOfBooks;
#Autowired
private ServiceImplementation(Config config) {
this.numberOfBooks = config.getNumberOfBooks();
}
}
In this way Spring creates the dependency tree and makes sure that Config is not null when injected.
I am attempting to use mocks in my integration test and am not having much luck. I am using Spring 3.1.1 and Mockito 1.9.0, and the situation is as follows:
#Component
public class ClassToTest {
#Resource
private Dependency dependency;
}
and
#Component
public class Dependency {
#Resource
private NestedDependency nestedDependency;
}
Now, I want to do an integration test of ClassToTest using Spring's JavaConfig. This is what I have attempted, and it doesn't work:
#Test
#ContextConfiguration
public class ClassToTestIntegrationTest {
#Resource
private ClassToTest classToTest;
#Resource
private Dependency mockDependency;
#Test
public void someTest() {
verify(mockDependency).doStuff();
// other Mockito magic...
}
#Configuration
static class Config {
#Bean
public ClassToTest classToTest() {
return new ClassToTest();
}
#Bean
public Dependency dependency() {
return Mockito.mock(Dependency.class);
}
}
}
I have simplified my setup to make the question easier to understand. In reality I have more dependencies and only want to mock some of them - the others are real, based on config imported from my prod #Configuration classes.
What ends up happening is I get a NoSuchBeanDefinitionException saying that there are no beans of type NestedDependency in the application context. I don't understand this - I thought Spring would receive Mockito's mocked instance of Dependency and not even look at autowiring it. Since this isn't working I end up having to mock my entire object graph - which completely defeats the point of mocking!
Thanks in advance for any help!
I had the same problem and I found another solution.
When Spring instantiate all your beans, it will check if it's a Mockito Mock and in this case, I return false for injection property. To use it, just inject it in a Spring context
Code below:
public class MockBeanFactory extends InstantiationAwareBeanPostProcessorAdapter {
private static final MockUtil mockUtil = new MockUtil();
public MockBeanFactory() {
super();
}
#Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return !mockUtil.isMock(bean);
}
}
What Mockito does when mocking classes is it creates a subclass using cglib having some fancy name like: Dependency$EnhancerByMockito (IIRC). As you probably know, subclasses inherit fields from their parent:
#Component
public class Dependency {
#Resource
private NestedDependency nestedDependency;
}
public class Dependency$EnhancerByMockito extends Dependency{
//...
}
This means Spring still sees the field in base class when presented with mock. What you can do:
Use interfaces, which will cause Mockito to employ dynamic proxies rather than CGLIB-generated classes
Mock NestedDependency - I know it will just cascade the problem one level further
Disable #Resource annotation scanning for tests