Mockito not mocking my #Autowired class - spring

I came across a problem, while mocking my class i get NullPointerException on mocked object and I cant figure out why mockito is not mocking only one class annotated by #Mock. Do someone have any idea what's the problem there ?
Tested class :
public class TimeoutJpaTransactionManager extends JpaTransactionManager {
private final String TRANSACTION_METHOD_NAME= String.join(".", ZapisPakietuReceptService.class.getName(), "transactionMethod");
#Autowired
private TransactionTimeoutConfig transactionTimeoutConfig;
public TimeoutJpaTransactionManager(EntityManagerFactory emf) {
super(emf);
}
protected int determineTimeout(TransactionDefinition definition) {
if (TRANSACTION_METHOD_NAME.equals(definition.getName())) {
return transactionTimeoutConfig.getSgr();
}
return super.getDefaultTimeout();
}
}
Autowired class :
#Getter
#Setter
#Component
#ConfigurationProperties(prefix = "transaction.timeout")
public class TransactionTimeoutConfig {
private int sgr;
}
Test class:
public class TimeoutJpaTransactionManagerTest {
#InjectMocks
private TimeoutJpaTransactionManager timeoutJpaTransactionManager;
#Mock
private EntityManagerFactory entityManagerFactory;
#Mock
private TransactionDefinition transactionDefinition;
#Mock
private TransactionTimeoutConfig transactionTimeoutConfig;
private final String TRANSACTION_METHOD_NAME_MOCK= String.join(".", ZapisPakietuReceptService.class.getName(), "transactionMethod");
private final int TIMEOUT_VALUE= 30;
#BeforeMethod
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testDetermineTimeout() {
//given
Mockito.when(transactionDefinition.getName()).thenReturn(TRANSACTION_METHOD_NAME_MOCK);
Mockito.when(transactionTimeoutConfig.getSgr()).thenReturn(TIMEOUT_VALUE);
//when
int result = timeoutJpaTransactionManager.determineTimeout(transactionDefinition);
//then
Assertions.assertThat(result).isEqualTo(TIMEOUT_VALUE);
}
}
Whats weird and i cant undestand is that by adding another line like that all seems to work and TransactionDefinition is really mocked :
#BeforeMethod
public void setUp() {
MockitoAnnotations.initMocks(this);
MockitoAnnotations.initMocks(this);
}

Thanks to the M. Deinum comment i was able to figure it out, it seems the problem was with mixing field and constructor injections. Solution is to either move dependencies to the constructor and then wire it there or modify the current test case to
#InjectMocks
private TimeoutJpaTransactionManager timeoutJpaTransactionManager;
#Mock
private TransactionDefinition transactionDefinition;
#Mock
private TransactionTimeoutConfig transactionTimeoutConfig;
private EntityManagerFactory entityManagerFactory;
private final String TRANSACTION_METHOD_NAME_MOCK= String.join(".", ZapisPakietuReceptService.class.getName(), "transactionMethod");
private final int TIMEOUT_VALUE= 30;
#BeforeMethod
public void setUp() {
entityManagerFactory = Mockito.mock(EntityManagerFactory.class);
timeoutJpaTransactionManager = new TimeoutJpaTransactionManager(entityManagerFactory);
MockitoAnnotations.initMocks(this);
}

Related

Spring Boot Unit Testing MockMvc Null Body

I am having dificulties with using MockMvc.
Here I have simple Service and controller classes:
Service:
#Slf4j
#Service
public class EmployeeService {
//...
public Employee GetSample() {
//...
//filling Employee Entities
return new Employee(
"Harriet"
, "random"
, 25);
}
}
controller:
#RestController
#RequestMapping(value = "/info")
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
#Validated
public class EmployeeController {
private final EmployeeService employeeService;
#PostMapping("/GetEmployee")
public ResponseEntity<Employee> GetEmployee() {
Employee employee = employeeService.GetSample();
return new ResponseEntity<>(employee, HttpStatus.OK);
}
}
Test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class EmployeeTestCase {
private MockMvc mockMvc;
#InjectMocks
private EmployeeController EmployeeController;
#Mock
private EmployeeService employeeService;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(employeeController).build();
}
#Test
public void getEmployee() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.post("/info/GetEmployee")).andDo(print());
}
}
when I try to use MockMvc I get null body. It seems employee is null. But I didn't understand why.
I thought that when test uses perform, it should initialise employee and later on it should't be null.
I tried to cut the code as much as possible. I hope it is not long.
Note : also tried to use Mockito.when(employeeController.GetEmployee()).thenCallRealMethod();
The #SpringBootTest annotation loads the complete Spring application
context. That means you do not mock your layers
(Services/Controllers).
If you wanted to test specific layers of your application, you could look into test slice annotations offered by Springboot: https://docs.spring.io/spring-boot/docs/current/reference/html/test-auto-configuration.html
In contrast, a test slice annotation only loads beans required to test a particular layer. And because of this, we can avoid unnecessary mocking and side effects.
An example of a Test Slice is #WebMvcTest
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = HelloController.class,
excludeFilters = {
#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
}
)
public class HelloControllerTest {
#Autowired
private MockMvc mvc;
#Test
public void hello() throws Exception {
String hello = "hello";
mvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string(hello));
}
#Test
public void helloDto() throws Exception {
String name = "hello";
int amount = 1000;
mvc.perform(
get("/hello/dto")
.param("name", name)
.param("amount", String.valueOf(amount)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name", is(name)))
.andExpect(jsonPath("$.amount", is(amount)));
}
}
However if you really wanted to load up the SpringBoot Application context, say for an Integration Test, then you have a few options:
#SpringBootTest
#AutoConfigureMockMvc
public class TestingWebApplicationTest {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello, World")));
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class AuctionControllerIntTest {
#Autowired
AuctionController controller;
#Autowired
ObjectMapper mapper;
MockMvc mockMvc;
#Before
public void setUp() throws Exception {
System.out.println("setup()...");
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Test
public void create_ValidAuction_ShouldAddNewAuction() throws Exception {
final Auction auction = new Auction(
"Standing Desk",
"Stand up desk to help you stretch your legs during the day.",
"Johnnie34",
350.00);
mockMvc.perform(post("/auctions")
.contentType(MediaType.APPLICATION_JSON)
.content(toJson(auction)))
.andExpect(status().isCreated());
}
}
Lets say you don't want to load up any layers at all, and you want to mock everything, such as for example a Unit Test:
#RunWith(MockitoJUnitRunner.class)
class DemoApplicationTest {
#Mock
private UserRepository userRepository;
private Demo noneAutoWiredDemoInstance;
#Test
public void testConstructorCreation() {
MockitoAnnotations.initMocks(this);
Mockito.when(userRepository.count()).thenReturn(0L);
noneAutoWiredDemoInstance = new Demo(userRepository);
Assertions.assertEquals("Count: 0", noneAutoWiredDemoInstance.toString());
}
}

MapStruct mapper not initialized with autowired when debug

I use spring boot 2.3.2 with mapstruct.
In a service class I have a mapper who have an autowired annotation.
#Service
public BillingService{
private BillingRepository billingRepository;
#Autowired
private BillingMapper billingMapper;
#Autowired
public BillingService (BillingRepository billingRepository){
this.billingRepository=billingRepository;
}
public void getBilling(Long billingId){
....
billingMapper.convertTo(...);
}
}
#RunWith(MockitoJUnitRunner.class)
public class BillingServiceTest{
#Mock
BillingRepository billingRepository;
private BillingService bilingService;
#Spy
private BillingMapper billingMapper = Mappers.getMapper(BillingMapper.class);
#BeforeEach
public void setup(){
MockitoAnnotations.initMocks(this);
billingService = new BillingService();
}
#Test
public void testGetBilling(){
List<Billing> billings = new ArrayList<>();
...
List<BillingPayload> payloads = new ArrayList<>();
when(billingMapper.convertTo(billings)).thenReturn(payloads);
bilingService.getBilling(1l);
}
}
#Mapper(componentModel="spring")
public interface BillingMapper{
...
}
When I debug and I'm stuck in getBilling method in BillingService Class, billingMapper is alway null;
You are using very strange configuration. First of all you have method returning BillingService that doesn't specify any return value so this would not even compile. I suggest following way:
#Service
public BillingService{
private final BillingRepository billingRepository;
private final BillingMapper billingMapper;
// constructor with bean injection
public BillingService(final BillingRepository billingRepository,
final BillingMapper billingMapper) {
this.billingRepository = billingRepository;
this.billingMapper = billingMapper;
}
public void getBilling(Long billingId){
....
billingMapper.convertTo(...);
}
}
Then you can configure your test like following:
#RunWith(SpringJUnit4ClassRunner.class)
public class BillingServiceTest {
#Spy private BillingMapper billingMapper = Mappers.getMapper(BillingMapper.class);
#MockBean private BillingRepository billingRepository;
#Autowired private BillingService billingService;
#TestConfiguration
static class BillingServiceTestContextConfiguration {
#Bean public BillingService billingService() {
return new BillingService(billingRepository, billingMapper);
}
}
#Test
public void testGetBilling(){
List<Billing> billings = new ArrayList<>();
...
List<BillingPayload> payloads = new ArrayList<>();
when(billingRepository.findById(1L)).thenReturn(); // someResult
when(billingMapper.convertTo(billings)).thenReturn(payloads);
bilingService.getBilling(1l);
}
}
#Mapper(componentModel="spring")
public interface BillingMapper{
...
}
Similiar configuration should work. Main problem is that you are mixing #Autowired with setter/constructor injection (don't know since your weird method inside BillingService. Also dont know why you use #Spy annotation when you are tryning to Mock interface. #Spy is used to mock actual instance, while #Mock is mocking Class type. I would stick with #MockBean private BillingMapper billingMapper instead if BillingMapper is specified as Bean in your application.

How to mock Feign Client

I can't mock my Feign Client using Mockito.
MyService.class
#Service
#AllArgsConstructor
public class MyService implements IMyService{
private static final Logger LOGGER = LoggerFactory.getLogger(MyService .class);
private final MyRepository repository;
private final MyFeignClient myFeignClient;
#Autowired
private MyDao myDao;
#Override
#Async
public void process(Map<UUID, Long> command) {
DocIds docIds = getDocIds(command.values().stream().findFirst().get());
archiveData(command.keySet().stream().findFirst().get(), documentIds.getIds());
}
private DocumentIds getDocIds(Long retentionId) {
return myFeignClient.getDocumentIds(retentionId);
}
private void archiveData(UUID execId, List<Long> docIds) {
List<MyDocument> myDocs= prepareMyDocs(docIds);
repository.saveAll(myDocs);
}
And my test class:
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("test")
public class ArchiveServiceTest {
#Autowired
ArchiveService archiveService;
#MockBean
MyDao myDao;
#MockBean
DocRepository archiveRepository;
#MockBean
private MyFeignClient myFeignClient;
#Test
public void shouldReturnTheSameNumberOfDocumentsToArchive() {
//given
List<DocData> documentData = prepareDocumentData();
// doReturn(new DocIds()).when(myFeignClient).getDocumentIds(1000L);
DocumentIds documentIds = new DocumentIds();
documentIds.setIds(Arrays.asList(1L, 2L));
when(myFeignClient.getDocIds(any())).thenReturn(documentIds);
when(documentDataDao.getAllDocumentData(anyList())).thenReturn(documentData);
doNothing().when(archiveRepository.saveAll(any()));
//when
Map<UUID, Long> command = new HashMap<>();
command.put(UUID.randomUUID(), 1000L);
archiveService.process(command);
//then
...
MyFeignClient:
#FeignClient(name = "myFeignClient", url = "${feign.searcher.path}")
public interface MyFeignClient{
#RequestMapping(method = RequestMethod.GET, path = "/document/path/{id}")
DocIds getDocumentIds(#PathVariable("id") Long id);
}
When running a test,
return myFeignClient.getDocumentIds(retentionId);
returns NULL. Why?
I don't have more ideas. I don't want to use WireMock. The same happens with my documentDataDao that doesn't return any values (null) specified in thenReturn() clause.
Have You tried it this way:
Mockito.when(myFeignClient.getDocumentIds(Mockito.eq(1000L))).thenReturn(new DocIds());
In You example, mock is commented out ;)
// doReturn(new DocIds()).when(myFeignClient).getDocumentIds(1000L);
But I'm sure it is just a bug in Your example.

Spring injection: #MockBean #Repository is not injected

I'm trying to #MockBean a #Repository annotated class:
#Repository
public interface ApplicationDao extends MongoRepository<Application, String> {}
I'm injecting it into a #Service annotated class:
#Service
public class AuthorizationService {
private ApplicationDao appsDao;
private List<Application> allowedApplications;
#Autowired
public AuthorizationService(ApplicationDao appsDao) {
this.appsDao = appsDao; //<<MOCKED INJECTED BEAN>>
this.fillApplications();
}
private void fillApplications() {
this.appsDao.findAll() //<<MOCKED method>>
.forEach(entry -> {
this.allowedApplications.put(entry.getName(), entry);
});
}
public bool isAuthorized(Application application) {
return this.allowedApplications
.stream()
.anyMatch(app -> app.getId().equals(application.getId()));
}
}
My test mocking configuration looks like:
#RunWith(SpringRunner.class)
#SpringBootTest()
public class GroupReferencesTest {
private #Autowired AuthorizationService;
private #MockBean ApplicationDao applicationDao;
#Before
public void setUp() {
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(this.applicationDao.findAll())
.thenReturn(allowedApplications);
}
#Test
public void test() {
Application app = new Application();
app.getId("test-application");
assertTrue(this.authorizationService.isAuthorized(app)); //<<FAILS>>
}
}
Nevertheless, my mocked object is not injected. I mean, when my AuthorizationService calls its injected ApplicationDao is returns an empty list instead of my mocked list.
I've tried to use #MockBean(name="applicationDao") as well. The behavior is the same.
I've also tried to configure my mocked bean using this code:
#TestConfiguration
public class RestTemplateTestConfiguration {
#Bean("applicationDao")
#Primary
public static ApplicationDao mockApplicationDao() {
ApplicationDao mock = Mockito.mock(ApplicationDao.class);
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(mock.findAll())
.thenReturn(allowedApplications);
return mock;
}
}
However, it doesn't works right.
Application class is:
public class Application {
private String id;
//setters & getters
}
Any ideas?
First things first - the type of test. Answer: Unit test.
You are starting Spring context that manages a lifecycle of AuthorizationService and then you are trying to inject mock. What really happens is that Spring IoC container is injecting a real ApplicationDao (the one managed by Spring IoC container) into the AuthorizationService.
Solution:
Manage lifecyle of AuthorizationService by your test runner (like MockitoJUnitRunner and inject ApplicationDao mock into it):
#RunWith(MockitoJUnitRunner.class)
public class GroupReferencesTest {
private #InjectMocks AuthorizationService authorizationService;
private #Mock ApplicationDao applicationDao;
#Before
public void setUp() {
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(this.applicationDao.findAll())
.thenReturn(allowedApplications);
}
#Test
public void test() {
Application app = new Application();
app.getId("test-application");
assertTrue(this.authorizationService.isAuthorized(app));
}
}
Working example
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {AuthorizationService.class})
public class GroupReferencesTest {
#Autowired
private AuthorizationService;
#MockBean
private ApplicationDao applicationDao;
#Test
public void test() {
//given
Mockito.when(applicationDao.findAll()).thenReturn(emptyList());
//when & then
assertTrue(authorizationService.isAuthorized(app));
}
}

Spring JUnit testing with #Autowired annotation

I´m having issues with my test cases after having introduced #Autowired in one of the classes under test.
My testcase now looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"/applicationContext.xml", "/spring-security.xml"})
public class StudentRepositoryTest extends AbstractDatabaseTestCase {
private StudentRepository studentRepository;
private CompanyRepository companyRepository;
private Student testStudent;
private Company testCompany;
#Before
public void setUp() {
studentRepository = new StudentRepository();
studentRepository.setJdbcTemplate(getJdbcTemplate());
testStudent = Utils.testStudentNoApplication();
}
#Test
....
}
StudentRepository now looks like this:
#Service
public class StudentRepository extends AbstractRepository<Student> {
...
private PasswordEncoder passwordEncoder;
private MailService mailService;
public StudentRepository() {
// TODO Auto-generated constructor stub
}
#Autowired
public StudentRepository(MailService mailService, PasswordEncoder passwordEncoder) {
this.mailService = mailService;
this.passwordEncoder = passwordEncoder;
}
Obviously this test case won´t work anymore.
But what changes do I need to make to the testcase for the #Autowired annotation to be picked up by the test case?
EDIT:
I´ve now updated my setUp() to this (I need the password encoder to avoid null password):
#Before
public void setUp() {
//studentRepository = new StudentRepository();
studentRepository = new StudentRepository(mock(MailService.class), ctx.getAutowireCapableBeanFactory().createBean(ShaPasswordEncoder.class));
studentRepository.setJdbcTemplate(getJdbcTemplate());
testStudent = Utils.testStudentNoApplication();
}
My testcase is now running OK, but my testsuite failes with a NullPointerException.
I´m guessing the ApplicationContext is not being Autowired when running the testsuite for some reason?
If you don't want to declare your StudentRepository in one of XML files referenced by #ContextConfiguration and autowire it into the test, you can try to use AutowireCapableBeanFactory as follows:
...
public class StudentRepositoryTest extends AbstractDatabaseTestCase {
...
#Autowired ApplicationContext ctx;
#Before
public void setUp() {
studentRepository = ctx.getAutowireCapableBeanFactory()
.createBean(StudentRepository.class);
...
}
...
}

Resources