How can Mockito mocks be wired when there is no constructor? - java

I was going through this tutorial which sets up the SUT using a constructor but my question is what if there is no constructor e.g. if we have:
#Autowire private PetRepository petRepository;
#Autowire private VetRepository vetRepository;
#Autowire private OwnerRepository ownerRepository;
#Autowire private VisitRepository visitRepository;
in the service/controller. How we can set this up?

I prefer to annotate the setters instead of the attributes on the classes. For example:
public class SomeClass implements SomeInterface {
private PetRepository petRepository;
private VetRepository vetRepository;
private OwnerRepository ownerRepository;
private VisitRepository visitRepository;
... some methods ...
#Resource
public void setPetRepository(PetRepository petRepository) {
this.petRepository= petRepository;
}
#Resource
public void setVetRepository(VetRepository vetRepository) {
this.petRepository= vetRepository;
}
#Resource
public void setOwnerRepository(OwnerRepository ownerRepository) {
this.ownerRepository = ownerRepository;
}
#Resource
public void setVisitRepository(VisitRepository visitRepository) {
this.visitRepository= visitRepository;
}
}
Then you can create a test case like this with Mockito and Junit:
public class SomeClassTestCase {
#Mock
private PetRepository petRepository;
#Mock
private VetRepository vetRepository;
#Mock
private OwnerRepository ownerRepository;
#Mock
private VisitRepository visitRepository;
private SomeClass someClass;
#Before
public void before(){
MockitoAnnotations.initMocks(this);
someClass = new SomeClass();
someClass.setPetRepository(petRepository);
someClass.setVetRepository(vetRepository);
someClass.setOwnerRepository(ownerRepository);
someClass.setVisitRepository(visitRepository);
}
#Test
public void someTest() {
...
}
}
Hope it helps.

You can use Mockito's #InjectMocks annotation. This will instantiate and then inject the Mock dependencies, for example:
#RunWith(MockitoJUnitRunner.class)
public ServiceTest {
#Mock
PetRepository petRepository
// ...omitted mocks ...
#InjectMocks
ClinicServiceImpl service;
}
See the documentation for further usage examples and caveats.

Related

Mockito: injected component returns null

I have an issue. I use Mockito Framework to test a service but I have to inject another service into it in order to work. The problem is that I get a NullPonterException when I try to use the second service. Is there a special way to inject the different mock objects into the two services. My code currently looks like this:
#ExtendWith(MockitoExtension.class)
public class Service1Test {
#Mock
Repository1 repository1;
#Mock
Repository2 repository2;
#Mock
Repository3 repository3;
#Mock
Repository4 repository4;
#InjectMocks
Service1 service1;
#InjectMocks
Service2 service2;
}
#Service
public class Service1Impl implements Service1 {
private final Repository1 repository1;
private final Repository2 repository2;
#Autowired
public Service1Impl (Repository1 repository1, Repository2 repository2) {
this.repository1; = repository1;
this.repository2; = repository2;
}
}
#Service
public class Service2Impl implements Service2 {
private final Repository1 repository1;
private final Repository2 repository2;
private final Repository3 repository3;
private final Repository4 repository4;
#Autowired
public PostServiceImpl(PostRepository postRepository, CommentRepository commentRepository, TagRepository tagRepository, CategoryRepository categoryRepository) {
this.postRepository = postRepository;
this.commentRepository = commentRepository;
this.tagRepository = tagRepository;
this.categoryRepository = categoryRepository;
}
}

How to reuse #MockBean definitions in Spring?

Is it possible to externalize #MockBean definitions, and combine them with composition instead of inheritance?
Because I find myself often repeating mock definitions, and I would rather be able to load/inject them and define them outside of the test class.
Example:
#SpringBootTest
public class Service1Test {
#MockBean
private Service1 service1;
#BeforeEach
public void mock() {
when(service1.call()).thenReturn(result1);
}
}
#SpringBootTest
public class Service2Test {
#MockBean
private Service2 service2;
#BeforeEach
public void mock() {
when(service2.call()).thenReturn(result2);
}
}
#SpringBootTest
public class Service3Test {
#MockBean
private Service1 service1;
#MockBean
private Service2 service2;
#BeforeEach
public void mock() {
when(service1.call()).thenReturn(result1);
when(service2.call()).thenReturn(result2);
}
}
I would like to externalize the mocks somehow, so I could just load them.
Pseudocode as follows:
public class MockService1 {
#MockBean
private Service1 service1;
#BeforeEach
public void mock() {
when(service1.call()).thenReturn(result1);
}
}
#SpringBootTest
#Import({MockService1.class, MockService2.class})
public class Service3Test {
}
Yes, you can achieve it by using an external configuration class. For example:
#TestConfiguration
public class TestConfig {
#Bean
#Primary
public Foo foo() {
return mock(Foo.class); //you can use Mockito or a different approach
here
}
#Bean
#Primary
public Bar bar() {
return mock(Foo.class);
}
}
#Import(TestConfig.class)
public class MyTestClass {
#Autowire
private Foo foo;
#Autowire
private Bar bar;
}

How to use #Inject?

Earlier i had the implemenation like:
public class FeedbackService {
private final FeedbackHelper feedbackHelper;
#Inject
public FeedbackService(FeedbackHelper feedbackHelper) {
this.feedbackHelper = feedbackHelper;
}
//rest of the class
}
Test file
public class FeedbackDataServiceTest {
private FeedbackService feedbackService;
#Mock private FeedbackHelper feedbackHelper;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.feedbackService = new FeedbackService(feedbackHelper);
}
}
It was workign fine. But when I changed to:
public class FeedbackService {
#Inject private FeedbackHelper feedbackHelper;
}
Test file
public class FeedbackDataServiceTest {
private FeedbackService feedbackService;
#Mock private FeedbackHelper feedbackHelper;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
}
The test cases started failing. Is anything else required to be done?
Use #InjectMocks to inject the mocks into the Service class.
public class FeedbackDataServiceTest {
#InjectMocks private FeedbackService feedbackService;
#Mock private FeedbackHelper feedbackHelper;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
}
There are three types of injection. The suggestion is to use constructor injection if the dependency is mandatory and setter injection if it is optional.
You can use #InjectMock on the under test object if you want to mock a field injection. But it is hard to test if you want to test without mocking framework.
#RunWith(MockitoJUnitRunner.class)
public class ApplicationTest
{
#InjectMocks
MainClass sut;
#Mock
DatabaseDAO dependentClassOne;
#Test
public void validateTest()
{
boolean saved = sut.save("abcd");
assertEquals(true, saved);
}

How to mock any services inside a #MockedBean?

Is it possible to just ignore/mock any injected dependencies inside a MockedBean?
Example:
#Service
public class MyService {
#Autowired
private MailerService mailer;
public void test1() {
//does not use mailer
}
public void test2() {
//...
mailer.send();
}
}
#Service
public class MailerService {
//I want these to be automatically mocked without explicit declaration
#Autowired
private JavaMailSender sender;
#Autowired
private SomeMoreService more;
//also these should be mocked without having to provide properties
#Value("${host}") private String host;
#Value("${user}") private String user;
#Value("${pass}") private String pass;
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class MyServiceTest {
#Autowird
private MyService myservice;
#MockBean
private MailserService mailer;
#Test
public void test1() {
myservice.test1();
}
}
I could use #MockBean to sort out mailer injection dependency. But any service inside the mocked bean would also have to be explicitly mocked.
Question: is it possible to mock a service "away". Means, just mock the bean and don't care what's inside the #MockedBean (or automatically also mock anything inside #MockedBean)?
As for me the best way to inject mocks is to use MockitoJUnitRunner
#RunWith(MockitoJUnitRunner.class)
public class MocksTests {
#InjectMocks
private ParentService parent;
#Mock
private InnerService inner; // this will be injected into parent
//your tests
}

Spy dependencies with Mockito

I have a bit of mess with Mockito and fields annotated with #Spy .
I want to test this class:
#Service
public class CategoryServiceImpl implements CategoryService {
#Autowire
private CategoryRepository categoryRepository;
private BoundMapperFacade<CategoryDTO, Category> boundMapper;
#Autowired
public void createMapper(final Mapper mapper) {
boundMapper = mapper.getMapperFactory().getMapperFacade(
CategoryDTO.class, Category.class);
}
// Rest of methods...
}
So, I have created a testing class as shown below:
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
#Spy
private BoundMapperFacade<CategoryDTO, Category> boundMapper;
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
// Rest of methods...
}
When Mockito instances categoryServiceImpl injects categoryRepository as a mock class but it does not know how to create boundMapper. This class depends on mapper, so I have rewritten my code:
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
private BoundMapperFacade<CategoryDTO, Category> boundMapper = spy(mapper.getMapperFactory().getMapperFacade(
CategoryDTO.class, Category.class));
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
// Rest of methods...
}
But now the problem is the creation of boundMapper is executed before Mockito injects mapper, so I get a NullPointerException.
So, is there any way to create an spy class who depends on another one and finally inject this last one in a field tagged as #InjectMocks?
If you have a spy that depends on a mock or a spy, the only way I've seen to do it is inside the #Before decorated function.
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
private BoundMapperFacade<CategoryDTO, Category> boundMapper = ;
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
#Before
public void setup() {
boundMapper = spy(mapper
.getMapperFactory()
.getMapperFacade(CategoryDTO.class, Category.class)
);
}
// Rest of methods...
}
I'm not sure how this works with #InjectMocks, so that might be something to look into. There might be a non-decorator version of it that you can run after boundMapper is initialized if CategoryServiceImpl is dependent on it.

Categories