#Mock/#InjectMocks for groovy - spock - java

In JUnit / Mockito we have 2 extremly useful annotations: #Mock and #InjectMocks.
In my new project i started using groovy with spock for testing, I'm wondering if there is a replacement for mentioned annotations?

There is no real need for #Mock in Spock, because there is already = Mock(), which can be used everywhere an annotation can be used (and also in other places). There is an open pull request for #InjectMocks, but it hasn't been decided if such a feature will make it into spock-core or spock-guice. (Shipping this feature with spock-guice, or at least requiring Guice on the class path, would allow to delegate injection to Guice, rather than reinventing the wheel.) If not, #InjectMocks could always be shipped as a third-party Spock extension.

Someone wrote an annotation two months ago: https://github.com/msid256/MockInjector4Spock.
The bean you want to test doesn't need to be instantiated manually. All you need to do is to declare it as a field and annotate it with #InjectMocks.
#Service
class ServiceC {
#Autowired
public ServiceC(ServiceA a, ServiceB b) {}
}
class DemoSpec extends Specification {
#Autowired
ServiceA serviceA;
ServiceB serviceB = Mock(ServiceB.class)
#InjectMocks // from MockInjector4Spock - de.github.spock.ext.annotation.InjectMocks
ServiceC serviceC;
}

https://github.com/marcingrzejszczak/spock-subjects-collaborators-extension
you can use #Collaborator and #Subject instead #Mock and #InjectMocks

In groovy there is no private scope, so we can modify the members of the class under test directly. So we can assign the member to our mocked value.

Related

When to use and not use #Mock annotation, #MockBean annotation, #InjectMock annotation & #Autowired annotation in a spring webflux reactive project

Can you please explain when to use below annotations and when not to use those. I am pretty new to testing frameworks and confused with all the answers in the web.
#Mock
private Resource resource;
#MockBean
private Resource resource;
#InjectMock
private ProductService productService;
#AutoWired
Private ProductRepository productRepo;
#Mock
Used to make Mockito create a mock object.
#InjectMock
When you want Mockito to create an instance of an object and use the mocks annotated with #Mock as its dependencies.
#AutoWired
Used when you want to autowire a bean from the spring context, works exactly the same as in normal code but can only be used in tests that actually creates an application context, such as tests annotated with #WebMvcTest or #SpringBootTest.
#MockBean
Can be used to add mock objects to the Spring application context. The mock will replace any existing bean of the same type in the application context. If no bean of the same type is defined, a new one will be added. Often used together with #SpringBootTest
So normally you either:
Use #Mock and #InjectMocks for running tests without a spring
context, this is preferred as it's much faster.
Use #SpringBootTest or #SpringMvcTest to start a spring context together with #MockBean to create mock objects and #Autowired to get an instance of class you want to test, the mockeans will be used for its autowired dependencies. You use this when writing integration tests for code that interact with a database or want to test your REST API.

Using SpringRunner with #Mock

I have read that when using #Mock, it should be used with #RunWith(MockitoJUnitRunner.class), while for #MockBean, it uses with #RunWith(SpringRunner.class).
However, for #Mock, I see that both MockitoJunitRunner or SpringRunner can be used interchangeably. I am rather confused as to why SpringRunner is also working in this situation ?
#RunWith(MockitoJUnitRunner.class) // also work when #RunWith(SpringRunner.class) is used
public class testService {
#InjectMocks
private ServiceA serviceA;
#Mock
private DependencyA dependencyA;
}
to quote this thread when talking about #MockBean
the class is included in the spring-boot-test library. It allows to add Mockito mocks in a Spring ApplicationContext.
Basically #MockBean is the combination of an #Mock and a #InjectMocks. Therefore, you could also use #Mock with springrunner but ofcourse it is not recommended because it is more heavy weight.
Generally you would use Mockito for lightweight unit tests, whereas using #MockBean when you want a mocked servlet environment like in a component test or a hybrid integration test.
Difference between #Mock, #MockBean and Mockito.mock()
typically, if you're using Spring Boot and need to mock a bean from the Spring ApplicationContext you would then use Spring Boot's #MockBean support instead of simply #Mock.
If your bean Injection happening via Autowired annotation, then #mock will not work.

Micronaut with MockitoTests

I have a requirement to test my service layer in Micronaut.
I am using bean validation in my service layer and so I need validator to be injected in the testing phase and I can't just mock it. However, I want to mock some other classes and so I am also using Mockito as well.
The problem is if I am putting #MicornautTest on my class all the beans marked with #Inject are Not-Null which means that #Inject is working fine. However, as soon as I add #ExtendWith(MockitoExtension.class) to the class and re-run the tests, all the means marked with #Inject are now null and all the beans marked with #Mock are Not-Null.
So it looks like either I can use #Inject in my tests or I can use #Mock but not both.
#MicronautTest
#ExtendWith(MockitoExtension.class)
class CashServiceTest {
#Inject
private Validator validator;
#Mock
private AvailableCashClient availableCashClient;
Has anyone faced similar issue earlier? Can you please guide me the correct configuration which will allow me to use both #Inject and #Mock in the same tests.
I was able to find the issue and was able to use both mocked beans and original injected beans.
The issue is we should not use #ExtendWith annotation and can achieve everything just by using #micronaut test.
I am pasting code for the set up which I did. In this case, BusinessClient is the bean which is being mocked and Validator is the bean which is injected without being mocked.
#MicronautTest
class CashServiceTest {
#Inject
AvailableCashClient availableCashClient;
#Inject
Validator validator;
#MockBean(AvailableCashClient)
public AvailableCashClient availableCashClient() {
return Mockito.mock(AvailableCashClient);
}

Using Mockito is necessary to overwrite all methods?

Using it to test in Spring.
Using #Mock Mockito is necessary to overwrite all methods replies of the original class with when clauses? And what is the difference with #MockBean ?
Its not accessory to override overwrite all methods.
#Mock is pure Mockito library where #MockBean is spring implementation of Mockito
So in your spring component class if not defined #Autowired fields (Just like simple java class to mock as object) then use #Mock annotation to mock the object of that class.
But your sping component class has #Autowired fields and you want spring container initialize that fields as Mock object then use #MockBean annotation (spring will do mock and autowire it).
For ex
class Test {
public void testMethod(){ -- some code --}
}
The you can use #Mock annotation for Test call to mock it. There is no other dependencies or fields in Test class.
#Component
class Test {
#Autowired
Other other;
public void testMethod(){ -- some code --};
}
Then you can mock Other object using #MockBean if you want to mock it and pass by the functionality of other (i.e we mock DAO layer and not calling actual logic). Spring container will initialize that other field.

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.

Categories