I use Scalamock for unit testing my Java project.
Project contains classes that use Java CDI style DI:
class Resource {
#Inject
private Service service;
.....
}
How can I inject mock as a Service instance?
With Mockito I'm able to use #InjectMocks, but I definitely want to use Scalamock.
Currently ScalaMock does not support Mockito's #InjectMocks equivalent.
In case of setter/constructor injection you can inject your mocks manually. In case of field injection you could access the private fields using reflection, but that would be very cumbersome.
Please create new ScalaMock feature request (https://github.com/paulbutcher/ScalaMock/issues) - if it gets upvoted we can implement it.
Related
I'm attempting to test a REST controller (using Quarkus) endpoint using rest assured. I want to mock a class that is injected into that controller (ideally with Mockio), but only for one of my tests. Or get different behaviour per test case without having to have separate classes for each test. I'm not sure how to do this?
I've seen doing it the way from the documentation:
#Mock
#ApplicationScoped
public class MockExternalService extends ExternalService {
#Override
public String service() {
return "mock";
}
}
But this would only allow me to use one mock for all tests and not mock certain behaviours based on tests as I would with Mockito. I think?
I've tried creating a mock and annotating it with #Mock
#Mock
public TableExtractorService tableExtractorServiceMock = Mockito.mock(TableExtractorService.class);;
but I still get my real implementation when I use it. I'm using a constructor annotated with #Inject in my Controller that takes the TableExtractorService.
For a bit more information my test using restassured looks like this:
InputPart filePart = Mockito.mock(InputPart.class);
Mockito.when(tableExtractorServiceMock.Extract(anyObject()))
.thenThrow(IOException.class);
final InputStream inputStream = filePart.getBody(InputStream.class, null);
given()
.multiPart("file", inputStream)
.when().post("/document")
.then()
.statusCode(500);
That endpoint calls the service class that I'm trying to mock, and I want that mock to return an exception.
It can't be done. Quarkus documentation explains the issue:-
Although this mechanism is fairly straightforward to use, it nonetheless suffers from a few problems:
A new class (or a new CDI producer method) needs to be used for each bean type that requires a mock. In a large application where a lot of mocks are needed, the amount of boilerplate code increases unacceptably.
There is no way for a mock to be used for certain tests only. This is due to the fact that beans that are annotated with #Mock are normal CDI beans (and are therefore used throughout the application). Depending on what needs to be tested, this can be very problematic.
There is a no out of the box integration with Mockito, which is the de-facto standard for mocking in Java applications. Users can certainly use Mockito (most commonly by using a CDI producer method), but there is boilerplate code involved.
Link for reference: https://quarkus.io/blog/mocking/
According Quarkus test documentation, you can do it usingo #QuarkusMock or #InjectMock.
As #Ankush said, a class annotated with the #Mock annotation is using the CDI #Alternative mechanism, and will be global. #QuarkusTestProfiles can be used to define CDI #Alternatives for groups of tests.
For example, instead of annotating the mock with #Mock, it could be referenced in a test profile as
default Set<Class<?>> getEnabledAlternatives() {
return Set.of(MyMockThing.class);
}
Any test annotatated with the
#TestProfile(MyMockyTestProfile.class)
profile would get those mocks, while others would use the original implementation.
What may be a simpler method is to just use #InjectMock. For example, in the test class, declaring a field like this:
#InjectMock
MyThing mock;
will ensure that mock is used by the classes under test, just for this test.
For rest clients, it will also be necessary to add a #RestClient annotation, and if the original implementation is a singleton, convertscopes can be used to coax the scopes into something mockable.
#RestClient
#InjectMock(convertScopes = true)
MyThing mock;
Behaviour can be added to the injected mock in #BeforeEach or #BeforeAll methods. For example
#BeforeEach
public void setup() {
when(mock.someMethod()).thenReturn("some value");
}
I have a class which I want to mock for a unit test. The class has a field with an #Autowired annotation. I need to inject that mock into a spring context that is being used in a junit. However, even though it's a mock, spring still sees the #Autowired and goes looking for an instance of this other class to inject. However, the context doesn't have an instance of that class, because one isn't needed (because the methods that might use that field are being mocked).
I've tried both XML and Java config, and in both cases the mock gets created and then spring still tries to find things to autowire into the mock (note I've set autowire=no in both cases).
XML that I've tried:
<bean class="org.easymock.EasyMock" factory-method="mock" autowire="no">
<constructor-arg value="com.stackoverflow.BeanClass" />
</bean>
Java config that I've tried:
#Bean(autowire = Autowire.NO)
public BeanClass beanClass1()
{
return EasyMock.createMock(BeanClass.class);
}
Note I've tried with both EasyMock and Mockito with the same results.
The only way I've found to do this is to do something like context.getBeanFactory().registerSingleton("name", mock) - but I can't do this if using SpringJUnit4ClassRunner.
Before anyone says "just don't do that", this is for an integration test rather than a pure unit test, and the complex wiring logic of some of the beans means that instantiating a spring context here saves a lot of duplicated effort in the test harness.
So, how can I stop spring trying to autowire beans into the fields of my mock?
When I was writing test case using the Mockito and Junit, I was using the #InjectMocks for the class to be tested. In other parts of project, I also see #Autowired is being used for the class to be tested.
When can I use #InjectMocks and #Autowired? What is the difference between two when we are trying to use them with class to be tested?
#InjectMocks is a Mockito mechanism for injecting declared fields in the test class into matching fields in the class under test. It doesn't require the class under test to be a Spring component.
#Autowired is Spring's annotation for autowiring a bean into a production, non-test class.
If you wanted to leverage the #Autowired annotations in the class under test, another approach would be to use springockito which allows you to declare mock beans so that they will be autowired into the class under test the same way that Spring would autowire the bean. But typically that's not necessary.
#InjectMocks annotation tells to Mockito to inject all mocks (objects annotated by #Mock annotation) into fields of testing object. Mockito uses Reflection for this.
#Autowired annotation tells to Spring framework to inject bean from its IoC container. Spring also uses reflection for this when it is private field injection.
You can even use even use #Inject annotation (part of Java EE specification) with the same effect.
But I would suggest to look at benefits of Constructor injection over Field injection. In that case you don't need to use #InjectMocks at all, because you can pass mocks into testing object via constructor. There wouldn't be Reflection needed under the hood in your test nor in production.
If you want to create integration test with subset of Spring beans I would suggest to take a look at #DirtiesContext annotation. It is part of Spring framework module commonly called "Spring Test".
Preface: My default mode of operation is using an IoC container and constructor injection. This makes testing with mocked dependencies trivial.
I am starting to develop an IntelliJ plugin and I want to make use of inversion of control. Since this is a plugin there isn't really an option of a container (right?) so I suppose I need to use a Service Locator pattern.
How do I test using mocks with the Service Locator pattern?
The best way that I can think of is to use an interface for my locator, set it in the default constructor of each service using a static getter, and have a setter so that I can set a mocked locator. It would look something like this:
public class MyService {
private IServiceLocator locator;
public MyService() {
setLocator(ServiceLocator.locator());
}
public void setLocator(IServiceLocator locator) {
this.locator = locator;
}
}
Now I can mock the IServiceLocator and set that on MyService in my test. I can then expect a call like locator.dependency1() and make it return a mocked dependency.
My main issue with this approach is the locator setter that is only there to support testing. Is there a better way?
First off I would suggest reading the excellent "Working Effectively With Legacy Code" which has a bunch of patterns for dealing with stuff like this. Although you're writing new code, you're bound by some of the same restrictions as legacy code.
For this, an easier way might be to provide a second protected constructor that accepts your dependencies explicitly and have the no-arg constructor use the defaults you want. So something like the following:
public class MyService {
private Dependency1 dep1;
private Dependency2 dep2;
protected MyService(Dependency1 dep1, Dependency2 dep2) {
this.dep1 = dep1;
this.dep2 = dep2;
}
public MyService() {
this(new ConcreteDependency1(), new ConcreteDependency2());
}
}
You can also add an annotation to make it clear this is for testing, i.e. Guava's #VisibleForTesting
You can do that in way you described. There are other options that comes into my mind:
You can use package-private access for service locator field
Now if you put your test class in the same package as service - it can directly manipulate fields inside tested class - so it is easy to mock service locator.
You can use features of testing/mocking library to inject service locator
For example Mockito (https://code.google.com/p/mockito/) can inject private fields int two ways:
Whitebox class - but this is not best idea since you have to know name of field that you want to mock (change of field name will break test), and you need to execute Withebox.setInternalState method manualy
#InjectMocks annotation - You create service locator field annotated with #Mock annotation, and service field annotated with #InjectMocks and mockito will use service locator field and injects it into service automatically.
You can use dependency injection mechanism that not depends on containers
For example check Google Guice library: https://code.google.com/p/google-guice/
You can use "manually" dependency injection
DI is pattern - DI containers/frameworks makes this pattern easy to implement, but you can always do it yourself with factory classes (but it takes more time). Here is nice talk about DI that covers "manual" DI: https://www.youtube.com/watch?v=RlfLCWKxHJ0
It is difficult to say which option is best for you. If you want to stick with service locator - I'd recomend Mockito. If you want DI - I'd recommend Google Guice. Personaly, I think that service locator is more like anti-pattern.
I am using Spring annotations in my code to do the DI. So lets say I have a class class1 that depends on another class class2, I define class1 as below:
#Component
public class class1 {
#Resource
private interface2 object2;
}
class2 is an implementation of interface2.
Now lets say I want to mock class2 and pass it to class1, I dont see any constructor or setter in class1. I think Spring uses reflection to inject object2. How can I mock it? Should I add a setter in class1? Or can I reuse the same way spring is doing it - I mean does spring itself have a mock object framework or something, I was planning to use EasyMock for the mocking.
Thanks
The ReflectionTestUtils class in Spring might be helpful.
It seems to do what you are looking for...at least the injection part :-)
Mockito has a really powerful way of handling mocks and DI:
#RunWith(MockitoJUnitRunner.class)
public class Class1Test {
#Mock
private Interface2 inteface2mock;
#InjectMocks
private Class1 class1;
#Test
public void someTest() {
when(interface2mock.doSomething("arg")).thenReturn("result");
String actual = class1.doSomeThatDelegatesToInterface2();
assertEquals("result", actual);
}
}
Read more about #InjectMocks in the Mockito javadoc or in a blog post that I wrote about the topic some time ago.
Available as of Mockito 1.8.3, enhanced in 1.9.0.
ReflectionTestUtils is the easiest to add the mock you want (we use JMock, but it does not really matter), drawback is that it is slightly brittle. If you rename the field, you must remember to change the test as well.
You can also use this: http://i-proving.com/2006/11/09/using-jmock-and-inject-object/
It describes how to use a mocked object in a spring context.
AFAIK, there is no mocking framework built into Spring, so you need to use something like EasyMock. The way I have done this in the past is to
Define the Spring config using XML instead of annotations*
The config for the main app is defined in appContext-main.xml and the test config (the mock objects) is defined in appContext-test.xml
A mock bean in appContext-test.xml must have the same ID as the corresponding bean in appContext-main.xml
When the app runs only appContext-main.xml is loaded
When the tests run both appContext-main.xml and appContext-test.xml are loaded. Make sure that they are loaded in this order so that the mocks 'override' any beans of the same name
* You don't need to need to convert all your Spring configuration to XML to use this approach. Only those beans that have mock implementations or have mock implementations injected into them need to be changed. The others bean can continue to be defined with annotations.
Injecting yourself via reflection is very easy, so you can avoid the setter method.
To do it yourself is like this:
for (Field field : injectable.getClass().getDeclaredFields()) {
MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
if (annotation != null) {
field.setAccessible(true);
Object param = generateMockObject();
field.set(injectable, param);
}
}
There is a JUnit Rule that gives EasyMock similar annotation-driven injection capabilities, in the manner of Mockito. See EasyMockRule