MockK - reinitialize mocks for each test - mockk

I have some mocks created using:
val someService = mockk<SomeService>(relaxed = true)
There are multiple tests in the file and I want the mock to be reset for each test
Is there currently a way to do this in MockK?
I know there is MockKAnnotations.init(this), but it didn't look like there was a way to set relaxed = true in the #Mock annotation

For resetting mocks in MockK you can use clearMocks. To create relaxed mock via annotation just check #RelaxedMockK

clearAllMocks() clears all mocks without the need of specifying them.

Related

Test for controller returning "ResponseEntity<StreamingResponseBody>" not seeing testdata

We have a controller returning a ResponseEntity<StreamingResponseBody>. When writing mockMvc tests for this controller we use .andDo(MvcResult::getAsyncResult).
For the controller to see the data we create in the database in the setup for the test we need to have #Transactional(propagation = Propagation.NEVER) on the test method.
We would prefere not to have this annotation, both to make the test run faster and for not having to clean up after it manuely.
Has anybody else here seen this issue and found a way of not having #Transactional(propagation = Propagation.NEVER) on the test method?

Spring boot test minimal test slice or manual configuration

I have many different SpringBoot tests running. So far the auto configuration slices were really helpful, especially in combination with #MockBean.
But in my current test no such slice fits and booting up the complete context using #SpringBootTest is too slow.
Is there a way to manually set the tip of the object tree to be started with and from there spring autowires all needed beans? Or is there a way to set all needed beans manually?
In my specific case i want to test a MapStruct generated mapper (using componentModel = "spring") this mapper uses two other mappers, each injecting a service to do their work.
The services are provided via #MockBean:
#RunWith(SpringRunner.class)
#SpringBootTest
public class ProductResponsibleUnitMapperTest {
#Autowired
private PRUMapper mapper;
#MockBean
private TradingPartnerService tradingPartnerService;
#MockBean
private ProductHierarchyService productHierarchyService;
#Test
public void mapForthAndBack(){
//works but takes ages to boot
}
}
I could not use constructor injection on the mappers (for the services) because MapStruct won't generate correct implementations.
How to get a Spring-Context only containing the needed beans?
I found one way by explicitly declaring all implementation used:
#SpringBootTest(classes = {ProductResponsibleUnitMapperImpl.class, LegalEntityMapperImpl.class, ProductHierarchyMapperImpl.class})
For more complex setups it will be cumbersome and also dangerous to declare generated classes.
I am still searching for a better cleaner way to let Spring decide what classes needed. It should be possible to set the class in hand and let Spring decide what classes needed and to be instantiated.

Spring auto populate list with mocks

I would like to know if anybody has successfully #Autowired an auto-populated list of objects, injecting mocks, with Spring during the test phase of the build? What I want to be able to do is override Spring's auto-population of a list during test time and have it populated with mocks within a unit test, instead of the implementation classes. I have successfully accomplished this by specifying #Resource within the code instead of #Autowired, but then when I deploy the Spring web app, the auto-population does not execute with #Resource specified for my list (it's just empty). The oppposite happens when I specify #Autowired on the list. The list is auto-populated when the app runs, but then I cannot populate the list with mocks when the unit tests run. It seems to be a catch-22...
So how do I use #Resource on a List type and have Spring still do the auto-population at runtime? Has anybody done this successfully - use auto-population at runtime, but substitute mocks into the list during the test phase? If so, could you possibly post relevant parts of your test #Configuration class? (Java annotations please, not XML). Thanks..
This works for injecting mocks, but then auto-population of the list doesn't kick in at runtime:
#Resource(name = "myServices")
private List<MyService> myServices;
And in my test config:
#Bean
#Qualifier("myServices")
public List<MyService> myServices() {
List<MyService> myServices = new ArrayList<>();
MyService mockService1 = Mockito.mock(MyService.class, Mockito.RETURNS_DEEP_STUBS);
MyService mockService2 = Mockito.mock(MyService.class, Mockito.RETURNS_DEEP_STUBS);
eventServices.add(mockService1);
eventServices.add(mockService2);
return myServices;
}
And then with the following, auto-population is active all the time (at runtime and during the test phase), but I cannot override and inject the mocks during the test phase with #Autowired, as it ignores the myServices #Bean definition from the test config:
#Autowired
#Qualifier("myServices")
private List<MyService> myServices;
Thanks in advance for any insight on this.

How does Mockito #InjectMocks work?

Here's my question:
I have several web services classes to test that all inherit their methods from a generic service. Rather than write a unit test for each, I figure I can break the test suite down by functional areas (i.e. three groups of test methods, each relying on a different underlying DAO method call).
What I propose to do is:
#Mock StateDAO mockedStateDao;
#Mock CountyDAO mockedCountyDao;
#Mock VisitorDAO mockedVisitorDao;
then call:
#InjectMocks CountyServiceImpl<County> countyService = new CountyServiceImpl<County>();
#InjectMocks StateServiceImpl<State> stateService = new StateServiceImpl<State>();
#InjectMocks VisitorServiceImpl<Visitor> visitorService = new VisitorServiceImpl<Visitor>();
How can I be sure that each mockedDAO will be injected into the correct service?
Would it be easier to autowire all three (rather than use #InjectMocks)?
I'm using Spring, Hibernate, and Mockito...
Well nicholas answer is almost correct, but instead of guessing just look at the javadoc of InjectMocks, it contains more details ;)
To me it's weird to have so many Service in a single test, it doesn't feel right, as a unit test or as an integration test. In unit test it's wrong because well you have way too much collaborators, it doesn't look like object oriented (or SOLID). In integration tests, it's weird because the code you test the integration with the DB not mock it.
For a rapid reference in 1.9.5 you have :
Mark a field on which injection should be performed.
Allows shorthand mock and spy injection.
Minimizes repetitive mock and spy injection.
Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below. If any of the following strategy fail, then Mockito won't report failure; i.e. you will have to provide dependencies yourself.
Constructor injection; the biggest constructor is chosen, then arguments are resolved with mocks declared in the test only.
Note: If arguments can not be found, then null is passed. If non-mockable types are wanted, then constructor injection won't happen. In these cases, you will have to satisfy dependencies yourself.
Property setter injection; mocks will first be resolved by type, then, if there is several property of the same type, by the match of the property name and the mock name.
Note 1: If you have properties with the same type (or same erasure), it's better to name all #Mock annotated fields with the matching properties, otherwise Mockito might get confused and injection won't happen.
Note 2: If #InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.
Field injection; mocks will first be resolved by type, then, if there is several property of the same type, by the match of the field name and the mock name.
Note 1: If you have fields with the same type (or same erasure), it's better to name all #Mock annotated fields with the matching fields, otherwise Mockito might get confused and injection won't happen.
Note 2: If #InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.
If you have multiple Services and would like to replace the DAOs with Mock-Objects in a Spring-based environment, I would recommend to use Springockito: https://bitbucket.org/kubek2k/springockito/wiki/Home
which is also mentioned here:
Injecting Mockito mocks into a Spring bean
Your Testclass then might look like this:
#RunWith (SpringJUnit4ClassRunner.class)
#ContextConfiguration (loader = SpringockitoContextLoader.class, locations = {"classpath:/org/example/package/applicationContext.xml"})
public class NameOfClassTest {
#Autowired
#ReplaceWithMock
StateDAO mockedStateDao;
#Autowired
#ReplaceWithMock
CountyDAO mockedCountyDao;
#Autowired
#ReplaceWithMock
VisitorDAO mockedVisitorDao;
In your #Test or #Before Methode you can setup your mocks the standard Mockito way:
Mockito.doReturn(null).when(mockedCountyDao).selectFromDB();
Well, the static method MockitoAnnotations.initMocks(Object) is used to bootstrap the whole process.
I don't know for sure how it works, as I haven't browsed the source code, but I would implement it something like this:
Scan the passed Object's class for member variables with the #Mock annotation.
For each one, create a mock of that class, and set it to that member.
Scan the passed Object's class for member variables with the #InjectMocks annotation.
Scan the class of each found member for members it has that can be injected with one of the mock objects created in (2) (that is, where the field is a parent class/interface, or the same class, as the mock objects declared class) and set it to that member.
Nevermind, looked online- the InjectMocks annotation treats anything with the #Mock annotation as a field and is static-scoped (class wide), so I really couldn't guarentee that the mocks would go to the correct service. this was somewhat a thought experiment for trying to unit test at feature level rather than class level. Guess I'll just autowire this stuff with Spring...

Commit/Flush transactions during unit test?

I am using Spring and JUnit to write some integration tests for my DAO. I set up my test data in the beginning of the test method, and then test my DAO methods later in the same test method. The problem is that if I don't flush/commit the transaction, the EntityManager returns the same instance of the entities that I have just created in my data setup - rendering my test useless as they will always pass.
E.g.
#Test
#Transactional()
public void loadTreeBasicCase() {
// creates and saved node to DB
Node n = createNode();
// test DAO
Node result = dao.lookup(n.getId());
// verify
assertThat(n, equalTo(result));
}
One way is to expose commit() and/or flush() methods in my DAO. But I would prefer not to do that because in production code, this almost never needs to happen (let EntityManager do it's thing). Is there a way to configure this via annotations or in Spring config? I am using Spring, JPA2 with Hibernate.
You can set the defaultRollback attribute on #Transactional to reset things between tests. This doesn't sound like what you are asking for, just throwing it out there first.
Within the test, the entity manager is behaving correctly. You want to inject different behavior for testing to "disconnect" the setup from the rest of the test. One thing I did in some tests was to call flush on the entity manager directly from the test. I only had to do it a few times, but it was valuable in those cases. I did it in the test (not the DAO) so as to not provide a method on the DAO that I don't want people calling.

Resources