I tried to user weld-junit5 with mocking a class.
I mock the class because i want to know how often it will be called.
But each time i try to Mockito.verify() this mocked class it throws a "NotAMockException"
The Intellij Debugger is validating the field as: "Mock for MessageService, hashCode: XY"
I already tried to add my testclass into the WeldInitiator but it dont want to work.
"MessageService" is a real class, not an interface (a Interface wouldn't work either)
Docs
#EnableWeld
class GameServiceTest {
#WeldSetup
public WeldInitiator weld = WeldInitiator.from(GameService.class, GameCache.class,
/** Some More **/,
GameServiceTest.class).build();
#Produces
#ApplicationScoped
public MessageService createMessageServiceMock() {
return mock(MessageService.class);
}
#Inject
private MessageService messageService;
#Inject
private GameService gameService;
#Test
void handleRunningGames() {
this.gameService.handleRunningGames(null, mock(Session.class));
// This will throw a org.mockito.exceptions.misusing.NotAMockException
Mockito.verify(messageService, Mockito.times(1)).writeMessage(any(), any());
}
}
I expect, that the Injected MessageService is a real mock, on which i can call every Mockito function, but it seems not so.
Do I anything wrong, or what is the proper way to do this?
I think I just resolved this problem:
private static final MessageService messageService = mock(MessageService.class);
#Produces
#ApplicationScoped
public MessageService createMessageServiceMock() {
return messageService;
}
To give some background, the way it works is that Weld lets Mockito create the desired object and then takes that as a contextual bean instance.
However, in CDI any bean that has normal scoped needs to have a proxy that is passed around instead of that instance. So what your producer actually does (because it is #ApplicationScoped) is create the object, store that in the context and then also create a proxy and pass around that proxy instead. The proxy is a different object (a delegate with no state) that "knows" how to get reference to the actual instance.
So what happens is that proxy gets injected into the field and you are checking the proxy object with Mockito.verify() call. Obviously, the proxy isn't the mock itself and so it fails. As user #second suggested, Weld offers an API to unwrap the proxy and get the contextual instance. I would argue that the API isn't "ugly", it is just a thing users shouldn't mostly care about but sometimes you cannot avoid it.
You could avoid having proxy by using some of the pseudo scopes which are #Dependent or CDI #Singleton. With that it should work as well and so long as it's for tests, replacing application scoped with singleton should work.
As for your workaround, I do no see how that solves anything - it is basically the same producer and because of the scope it will only be invoked once, hence the static field will make no difference (as there will be a singular call to mock creation). Have you changed something else than that?
As a user of JUnit 5 + Weld-JUnit myself, I am using the following pattern. The reasons are those explained in the answer by Siliarus.
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.Mock;
import ...
#EnableWeld
#ExtendWith(MockitoExtension.class) // (1)
class GameServiceTest {
#WeldSetup
public WeldInitiator weld = WeldInitiator.from(GameService.class, GameCache.class,
/** Some More **/,
GameServiceTest.class).build();
#Produces
#ApplicationScoped // (2)
#Mock // (3)
private MessageService messageServiceMock;
// #Inject // (4)
// private MessageService messageService;
#Inject
private GameService gameService;
#Test
void handleRunningGames() {
this.gameService.handleRunningGames(null, mock(Session.class));
// (5)
Mockito.verify(messageServiceMock, Mockito.times(1)).writeMessage(any(), any());
}
}
Explanations:
I am using the Mockito extension for convenience
You do not really need to give it application scope
The #Mock annotation is handled by the MockitoExtension. Again, this is only for convenience, you could create the mock yourself in a producer method.
You do NOT need to inject the mock service; you have the messageServiceMock! The injected thing here will be the Weld proxy, as explained by Siliarus.
It is fun to describe this injection a bit more: If the bean is #ApplicationScoped, i.e. "normal-scoped", CDI has to inject a proxy. If you use this proxy instead of the actual mock, you will get the exception. If you follow my advice from (2) and leave out the #ApplicationScoped, the bean will be dependent-scoped and the mock is injected directly. In this case you could use the injected field, but why bother?
Use the mock directly.
Related
I have an SpringBoot application that consists of a Controller layer and a Service layer.
MyController has access to MyService via #Autowired, while MyService has a method that creates a new instance of MyClass, which is imported from an external dependency.
import externaldependency.MyClass;
#Service
public class MyService {
public void myMethod() {
MyClass c = new MyClass();
c.doStuff();
c.doOtherStuff();
c.doMoreStuff();
}
}
I use new to create the instance because MyClass holds state; it has several methods that change its state during the execution of myMethod until I get the desired result, therefore I shouldn't autowire it nor inject it in the constructor, since that would use a single instance of this class for every call to myMethod. I understand that "Prototype" beans exists, but as far as I know, even if I declare MyClass as a prototype bean and inject it to MyService via #Autowired, the service would still use the same instance of MyClass during execution, so ultimately I decided to just use new.
Recently I've been trying to do an integration test, calling my Controller layer, which in turn will call my Service layer, which in turn will create an instance of MyClass. The problem is that one of the many methods of MyClass internally calls an external service, which shouldn't be part of the test itself, so I would like to mock this class.
I understand that mocking is done via dependency injection, but in this case I can't do that. Is there an alternative way to mock MyClass, or is it simply not possible with this setup? If not, then how could I refactor my code to make mocking possible in this particular case?
Many thanks in advance.
I'll answer my own question.
Since MyClass holds state, it shouldn't be autowired to the service nor injected via its constructor, but rather new instances should be created as needed. However, whan can be autowired is a "factory" which creates these instances:
#Component
class MyClassFactory {
public MyClass getInstance() {
return new MyClass();
}
}
Therefore, the service becomes:
#Service
public class MyService {
#Autowired
private MyClassFactory myClassFactory;
public void myMethod() {
// MyClass c = new MyClass();
MyClass c = myClassFactory.getInstance();
c.doStuff();
c.doOtherStuff();
c.doMoreStuff();
}
}
In practice, using a factory is the same thing as just using new; I'm getting a new instance either way. The benefit comes during testing; now I can mock what the factory returns, since the factory is part of Spring's application context:
#SpringBootTest
public class MyTest {
#MockBean
private MyClass myClassMock;
#MockBean
private MyClassFactory myClassFactoryMock;
#Test
public void myTests() {
// Make a mock of MyClass, replacing the return
// values of its methods as needed.
given(
myClassMock.doStuff()
).willReturn(
"Something useful for testing"
);
// Then make a mock of the factory, so that it returns
// the mock of the class instead of a real instance.
given(
myClassFactoryMock.getInstance()
).willReturn(
myClassMock
);
// Do the tests as normal.
}
}
Probably not the most elegant solution, but at least solved my current problem.
One of the really cool and rather mind boggling features that I have recently discovered in Spring is self auto-wiring a bean.
What I am referring to is this:
class UserServiceImpl implements UserService {
#Autowired
UserService service;
// other service methods...
}
My questions are as follows:
How is this implemented ?
How does Spring manage this ? Does it assign the same object to self auto-wire reference ? Like so:
UserServiceImpl serviceImpl = new UserServiceImpl();
serviceImpl.setService(serviceImpl); // Obviously this would be done via Reflection rather than a setter.
or
does Spring make 2 seperate objects? Like so :
UserServiceImpl obj1 = new UserServiceImpl();
UserServiceImpl obj2 = new UserServiceImpl();
obj1.setService(obj2);
And just gives us obj1 when we request it in a RestController ?
How many copies of the object are there in the Spring Application Context ?
Related to the previous question, how many actual copies of the object are there ?
Its a very convenient feature for things like transactions across methods, but I want to know what is exactly going on behind the scenes here.
It doesn't inject the UserServiceImpl if you use some annotation like #Transactional,#Cachable etc. It actually injects the proxy.
But as the base it uses the same instance.
As of 4.3, #Autowired also considers self references for injection (that is, references back to the bean that is currently injected). Note that self injection is a fallback. Regular dependencies on other components always have precedence. In that sense, self references do not participate in regular candidate selection and are therefore in particular never primary. On the contrary, they always end up as lowest precedence. In practice, you should use self references as a last resort only (for example, for calling other methods on the same instance through the bean’s transactional proxy). Consider factoring out the affected methods to a separate delegate bean in such a scenario. Alternatively, you can use #Resource, which may obtain a proxy back to the current bean by its unique name.
There is only one copy and uses reflection
Lets look at this sample
#Service
public class SampleService {
#Autowired
private SampleService service;
public SampleService getService() {
return service;
}
}
#SpringBootApplication
public class RestServiceApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context
= SpringApplication.run(RestServiceApplication.class, args);
SampleService sampleService = context.getBean(SampleService.class);
//This will print true
System.out.println(sampleService == sampleService.getService());
}
}
As you can see sampleService == sampleService.getService() is true;
I am learning Spring, and as far as I understand, when we use #annotation on a method which has a generic name (not a setter method), then the method's arguments are autowired.
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
#Autowired
public void prepare(MovieCatalog mC,
CustomerPreferenceDao cPD) {
this.movieCatalog = mC;
this.customerPreferenceDao = cPD;
}
// ...
}
So, here, the fields movieCatalog and customerPreferenceDao are autowired with the values of mC and cPD. What I fail to understand is how is this different from the same method without the "#autowired".
I understand #autowired when applied to a Field name, but not able to understand when the values are explicitly being passed to the method (either a setter or any other method), then what does Spring do special?
quite late answer, but here it is:
any method annotated with #Autowired is a config method. It is called on bean instantiation after field injection is done. The arguments of the method are injected into the method on calling.
The #autowired method you have provided does not need to be invoked from within your own code. It will be invoked by the Spring framework. Imagine a setter method in a class that is declared as #autowired. The setters parameter is provided by Spring. So before using the class object instance you do not have to write code to call the setter method, just like you don't need to provide the parameters of an #autowired constructor. There are lots of things you can do with autowired. Check out these two examples:
Calling #autowired method
Other uses of #autowired
One of the advantages of #autowired is that you do not have to instantiate the object, as Spring Framework will do that for you. But not only that, an #autowired object is managed by the Spring Framework, so you don't have to worry about handling of object instances, cause Spring does it for you. So it saves a lot of coding and unnecessary code that is often used to keep track of and manage the objects. Hopefully this was of some help.
#autowired on a method is used for setter-injection. it is not different from field injection besides that the beans is not that dependent on the spring-container, you could instantiate and wire it yourself as well.
one reason to use it is if you have circular dependencies.
another use of setter injection is that it allow re-injection of (a possibly optional) dependency at a later time (JMX).
public class MovieRecommender {
#Autowired
private MovieCatalog movieCatalog;
#Autowired
private CustomerPreferenceDao customerPreferenceDao;
}
Now you have no need for a prepare method!
I've seen the #Autowired annotation placed just before the constructor of a POJO used as controller.
#Controller
public class LoginController{
private UsuarioService usuarioService;
#Autowired
public void LoginController(UsuarioService usuarioService){
this.usuarioService = usuarioService;
}
// More code
}
This constructor takes as argument the reference to the object we want Spring to inject.However if I place this annotation just before the property declaration the application works just the same.
#Controller
public class LoginController{
#Autowired
private UsuarioService usuarioService;
// More code
}
My question is what is the difference between this two approaches in terms of pros and cons.
My advice to you would be to never use #Autowired on fields (except in Spring #Configuration classes).
The reason is very simple: TESTING!!!!
When you use #Autowired on fields of a class, then that class becomes harder to unit test because you cannot easily use your own (possible mocked) dependencies for the class under test.
When you use constructor injection then is becomes immediately evident what the dependencies of the class are, and creating that class becomes straight forward (simple constructor call).
Some points that need to made:
1) Some might argue that even when #Autowired is used the class can still be unit tested with the use of Mockito's #InjectMocks, or Spring's ReflectionTestUtils.setField, but my opinion is that the creation of a unit under test should be as dead simple as possible.
2) Another point that could be mentioned is that there might be many arguments in the constructor making the manual invocation of the constructor (either in the test or elsewhere) difficult. This however is not a problem regarding the creation of the class, but a problem in the design. When a class has to many dependencies, in most cases it is trying to do too much and needs to broken into smaller classes with fewer dependencies.
#Autowired annotation on setter methods is to get rid of the element in XML configuration file. When Spring finds an #Autowired annotation used with setter methods, it tries to perform byType autowiring on the method
#Autowired annotation on properties is to get rid of the setter methods. When you will pass values of autowired properties using Spring will automatically assign those properties with the passed values or references.
Here is an example of both the usage:
http://www.tutorialspoint.com/spring/spring_autowired_annotation.htm
This Springsource blog post mentions that constructor injection makes it easy to validate required dependencies, if used in combination with contructors assertions that are good practice anyway and would also work if the class is instantiated outside Spring with the new operator:
#Controller
public class LoginController{
private UsuarioService usuarioService;
#Autowired
public void LoginController(UsuarioService usuarioService){
if (usuarioService == null) {
throw new IllegalArgumentException("usuarioService cannot be null.");
}
this.usuarioService = usuarioService;
}
}
This type of assertions are general best practice that is advised to do independently of the class being a Spring bean or not.
For setter or property injection there is also the #Required annotation for validating missing dependencies or #Autowired(required = true). According to the blog post, constructor injection provides this advantage, but for historical reasons setter injection is more frequently used in Spring.
I have so controller
#Controller
public class MyController {
#Autowire
MyClass myClass;
//myClass doesn't have setter and getter
....
#RequestMapping("/path")
public String underTest(){
myClass.makeSomething();
return "html.jsp"
}
I want make mock test using Mockito and mock myClass.
In test class I want get myClass so:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/BeanConfig.xml");
myClass = context.getBean("myClass ", MyClass .class);
But I need autowire this bean to Controller for testing controller's method(I think test code should not affect to normal code).
There are exist way to make it without writing of set method?
I want to check that myClass.makeSomething() invokes once in method underTest.
As long as your test for MyController resides in the same package as MyController itself (as it's usually done - same packages in different source folders), you can simply assign it:
MyController controller = new MyController();
controller.myClass = mockMyClass;
That's the reason not to put #Inject/#Autowired on private fields.
I'm not sure I agree with you that test code should not affect normal code. I think an entirely valid reason to refactor / rewrite production code is to make it more testable (this is probably achieved by making it more modular, which is generally a good thing anyway).
This is precisely why annotations like
#VisibleForTesting
exist. Then you can create a package-local setter for MyClass, add the above annotation (for information to other programmers and possibly code inspection tools) and set the field in your test (which should reside in the same package).
Alternatively, since you are using Mockito, you could simply annotate the MyController instance with #InjectMocks, eg
#Test
public class MyControllerTest {
#Mock
private MyClass mockMyClass;
#InjectMocks
private MyController myController;
#BeforeMethod
public void before() {
MockitoAnnotations.initMocks(this);
}
// do tests...
}
Note that #InjectMocks does not depend on any annotations on the target field (i.e. #Autowired, #Resource, #Inject etc). It just works. (Presumably you will still need those annotations for Spring injection, so don't remove them! The point is you can also use it for fields that aren't annotated).
Note also that, depending on which version of Mockito you are using, you may need to instantiate the MyController in the before() method before calling MockitoAnnotations.initMocks()
Try testing the controller directly with context.getBean(). MyClass will be autowired into it.
I agree with #axtavt's answer, however if you absolutely want to go your way with injecting the mock in an integration test, you can do this:
define a overriding bean configuration file, say bean-test-config.xml, with content along these lines:
<import resource="classpath:spring/BeanConfig.xml"/>
<bean name="myClass" factory-method="mock" class="org.mockito.Mockito">
<constructor-arg value="MyClass"></constructor-arg>
</bean>
This should correctly inject in a mock in your controller. You will have to get hold of this mock in your test and inject in any behavior that you are expecting from this mock though.