I'd like to use Mockito to unit test an abstract class as detailed in this great answer.
The trick is, the abstract class has a dependency on a strategy that gets injected in its constructor. I've created a mock of the strategy and I'd like for my mocked instance of BaseClass to use the mocked strategy for my unit test.
Any suggestion as to how I can wire this up? I'm not currently using any IoC framework, but am considering Spring. Perhaps it would do the trick?
// abstract class to be tested w/ mock instance
abstract BaseClass
{
// Strategy gets mocked too
protected BaseClass( Strategy strategy)
{
...
}
}
Update:
According to the Mockito mailing list, there currently isn't a way to pass arguments to the constructor of a mock.
I ended up just using reflection to set a private field in my base class, like so:
// mock the strategy dependency
Strategy strategyMock = mock( Strategy.class);
when(....).thenReturn(...);
// mock the abstract base class
BaseClass baseMock = mock(BaseClass.class, CALLS_REAL_METHODS);
// get the private streategy field
Field strategyField = baseMock.getClass().getSuperclass().getDeclaredField("_privateStrategy");
// make remove final modifier and make field accessible
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(strategyField, strategyField.getModifiers() & ~Modifier.FINAL);
strategyField.setAccessible(true);
// set the strategy
strategyField.set(baseMock, strategyMock);
// do unit tests with baseMock
...
It would break if the name of the private field ever changed, but its commented and I can live with that. It's simple, it;s one line of code and I find this preferable to exposing any setters or having to explicitly subclass in my tests.
Edit: So it's not one line of code anymore since my private field needed to be 'final', requiring a some extra reflection code to get around.
Ive seen this sort of thing done using Mockito at a spring context level.
eg:
<bean id="myStrategy" name="myStrategy" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="Strategy" />
</bean>
I hope that helps.
You don't need to do anything special. Just mock the bean like normal:
Bean bean = mock(Bean.class);
when(bean.process()).thenReturn(somethingThatShouldBeNamedVO);
Just works :)
Related
On the first screenshot you can see my test class. This class is annotated with #ExtendWith({MockitoExtension.class}) and also the tested service is annotated with #InjectMocks. On the second screenshot you can see the tested service.
Why does Mockito uses the long supplier in both cases?
Mockito uses different strategies when injecting mocks in this order:
Constructor injection
Property setter injection
Field injection
Field injection will not work in your example, since the service's fields are declared final.
Since the fields are declared final and the code snippet you showed does not have a field initializer, I assume that you have a constructor with the Supplier args. E.g.
public SomeService(Supplier<String> stringSupplier, Supplier<Long> longTimeSupplier) {
this.stringSupplier = stringSupplier;
this.longTimeSupplier = longTimeSupplier;
}
Thus Mockito will try the constructor injection, find the constructor with the two Supplier parameters and tries to resolve the arguments.
Mockito then finds the two Supplier mocks in the test, but it can not see the generic type due to type erasure. Thus Mockito sees the constructor like this:
public SomeService(Supplier stringSupplier, Supplier longTimeSupplier)
Mockito can also not decide which Supplier to use based on the parameter name, because the normal Java reflection API does not provide that information. So the name of the mocks, will not be taken into account.
There are libraries like paranamer that read the bytecode and extract the debug information to read the parameter names, but Mockito doesn't use that libs.
Thus Mockito just injects the first matching mock which is Supplier<String> stringSupplier in your case. Even your issues is related to generics, Mockito would also act the same way when you have two parameters of the same type that are not generic.
I assumed that you have a constructor that takes the two Supplier. So you can just invoke it in your test's before.
#BeforeEach
public void setup() {
service = new SomeService(stringSupplier, longSupplier);
}
If you can not access the constructor, e.g. it has package scope, you need to invoke it using reflection and set the accessible property to true
#BeforeEach
public void setup() throws Exception {
Constructor<SomeService> constructor = SomeService.class.getConstructor(Supplier.class, Supplier.class);
constructor.setAccessible(true);
service = constructor.newInstance(stringSupplier, longSupplier);
}
PS If you want to remove the final, make sure that the mocks are either named after the fields in the service longTimeSupplier vs. longSupplier or you use #Mock(name = "longTimeSupplier").
I was kind of lazy and used to use almost entirely field injections. I was just providing empty constructor, put my #Inject fields I everything was looking nice and simple. However field injection have its trade-offs so I've devised some simple rules that help me to decide when to used field and when to use constructor injections. I will appreciate any feedback if there is mistake in my logic or if you have additional considerations to add.
First some clarification in order to be on the same page:
Constructor injection:
#Inject
public SomeClass(#Named("app version") String appVersion,
AppPrefs appPrefs) {...
Same with the field injection:
public class SomeClass {
#Inject
#Named("app version") String mAppVersion;
#Inject
AppPrefs appPrefs;
Rule 1: MUST use field injection if I don't control creation of the object (think Activity or Fragment in Android). If some (non-dagger aware) framework is creating my object and handles it to me I have no choice but to inject it manually after I receive the instance.
Rule 2: MUST use constructor injection if the class is/may be used in another project that does not use Dagger 2. If the other project(s) do not use Dagger they cannot use DI so the user have to create the object the "old" way using new.
Rule 3: PREFER constructor injection when working with class hierarchies because it is easier to create unit tests.
Clarification:
Considering the following structure that uses field injection:
package superclass;
public class SuperClass {
#Inject
HttpClient mHttpClient;
...
}
.
package differentpackage;
public class SubClass extends SuperClass {
public SubClass() {
}
}
When I am creating unit test for SubClass in directory test/java/differentpackage I have no choice but to bring up the entire DI infrastructure in order to be able to inject the HttpClient. In contrast, if I was using constructor injection like this:
public class SuperClass {
private final HttpClient mHttpClient;
#Inject
public SuperClass(HttpClient httpClient) {
mHttpClient = httpClient;
}
}
in my unit test I could simply:
HttpClient mockHttp = mock(HttpClient.class);
Subclass tested = new Subclass(mockHttp);
// tests
So basically now I am in the other extreme: I tend to rely mostly on constructor injections and use field injections only when 'Rule 1' applies.
The only 'problem' that I have with the constructor injects is that for 'end' classes constructors sometimes become quite overloaded with parameters and they look verbose and ugly like this:
#Inject
public ModelMainImpl(#Named("app version") String appVersion,
AppPrefs appPrefs,
LoginPrefs loginPrefs,
#ForApplication Context appContext,
NetworkInfoProvider networkInfoProvider,
AndroidEventPoster androidEventPoster,
Session session,
ForgeExchangeManager exchangeManager,
HttpFunctionality httpFunctionality,
#Named("base url") String baseUrl,
#Named("forge result producer") ResultProducer<ForgeExchangeResult> resultProducer
) {
Guys, what are your rules to choose between constructor and field injects? I am missing something, are there errors in my logic?
Use constructor injection. if you can't, use property injection.
Rule 1 seems ok, like decorations or attributes you can use Property(field) injection.
Rule 2 seems ok, because who uses your class they have to follow your constructor. They may not know they have to intilaize your property also.
Rule 3 It's not just good for unit test. It's good for applying Single Responsibilty. It's easier to see your object graph.Otherwise you will hide it with property.
If we come in your question, yes there a lot of parameters in your constructor. But the solution is not property injection. You can refactor your code and use aggregate services
I have a class which takes a message with payload String.
The payload is then split and used to create an Entity which is passed to DAOInterface to persist.
How can you test the call daoInterface.insert(entity) has been made?
To Mock the DAOInterface and then verify the call to DAO requires the entity in the test class i.e.
verify(daoInterface).insert(entity);
Is this bad design i.e. creating the entity at this stage? Should the Sting[] split be passed to the DAOImplementaion and initialized there. Example problem,
public class ServiceClass {
#AutoWire
private DAOInterface daoInterface;
public void serviceMessage(Message<String> message) {
MessageHeaders mh = new MessageHeaders(message.getHeaders());
String[] split = ((String) mh.get("payload")).split("_");
code omitted
...
String type = mh.get("WhatType");
Entity entity = new Entity(split[0], split[1], split[2]);
if (type.equals("one"))
{
daoInterface.insert(entity); //How to test?
}
else
{
if (type.equals("two"))
{
doaInterface.modify(entity); //How to test?
}
}
}
}
You can verify with Mockito Matchers.
If you only care that the method is called with some Entity, you can verify that with
verify(daoInterface).insert(any(Entity.class));
If you care about which Entity, and the Entity class has an equals method, you can make an entity that should be equal to the one created and verify with
verify(daoInterface).insert(eq(expectedEntity);
If it's more complex than either of these cases, you can also write your own argument matchers.
The easiest thing you can do is injecting another collaborator to the service which will transform payload to Entity. This way you can keep control on object creation (Inversion of Control). Something like the example below injected to the ServiceClass should do the job:
interface PayloadTransformer {
public Entity transform(String payload);
}
This way your code will be easy to test and you split responsibilities which is usually a good thing. Have a look on Single Responsibility principle
Pushing transformation logic down to dao is almost never a good idea.
BTW. you can write else if without additional brackets and indentations. It's more readable like:
if (a) {
// do something
} else if (b) {
// do something
} else {
// do something
}
The last advice ServiceClass is really poor name for class. The word class is redundant here. Just name it Service, EntityService, MessageService or something which fits your case well.
I wouldn't name field with suffix *Interface as well. Underneath is some implementation injected, I assume. Better name it entityDao or just dao. It's up to you though :)
If you use a test framework like PowerMock, you can invoke private constructors and private methods in your test. This makes it easy to inject mock objects like a mock DAOInterface so you can retrieve it later and test it's been called.
For example, in PowerMock, to call a private constructor:
public class ServiceClass{
#Autowire
private final DAOInterface dao;
public ServiceClass() {
}
private ServiceClass(DAOInterface dao) {
this.dao = dao;
}
}
You simply do:
PrivateConstructorInstantiationDemo instance = WhiteBox.invokeConstructor(
PrivateConstructorInstantiationDemo.class,
new MockDAOInterface() );
So if you're using a dependency inject framework like above, this dovetails nicely. You don't normally have the dependency injection working during test, since it usually requires booting a large chunk of code with a lot of configuration.
By adding a single private constructor, you avoid breaking encapsulation, but you can still inject your mock object into the code during test with a test framework like PowerMock. This is considered best practice.
You could break encapsulation and add publicly accessible methods or ctors to the SeviceClass, but if you don't need them for your design it's not good practice to add them only for test. That's why people put such effort into bypassing encapsulation in frameworks like Mockito and PowerMock. It's not just a dodge around private code, it's because you want to keep the encapsulation while still being able to test.
EDIT:
If you're not familiar with making mock objects, you should do some Google searches on the subject. It's very common and a good skill to have. With the above code, you could make your own mock object. But making mocks is so common that most test frameworks will do this for you.
For example, in PowerMock, I just looked at their page on making mocks here. You can make a mock like this
DAOInteface myMock = createMock(DAOInterface.class);
You can then ask the mock to verify that methods are called:
expect(myMock.someMethod());
Now the mock 'expects' that method to be called, and if it isn't, it'll generate an error for your test. Pretty sweet actually.
You can also return values from a call:
expect(myMock.insert()).andReturn("Test succeeded");
so your code would then see the value "Test succeeded" when it called that method. I don't see that 'insert' does return a value, that's just an example.
Is there a simple way to inject simple primitive type parameters (string and int) to the beans?
What i need is to find the guice equivalent of something like this from spring.xml:
<bean id="aBean" ...>
<property name="fieldName" value="aStringValue"/>
<property name="anotherFieldName" value="123"/>
</bean>
The values could be constructor injected, field injected or method injected, but i don't want to use separate named annotation or factory or provider for every value that i need to pass to the bean.
EDIT: my solution
Here is what i finally came to. I think it is closest to what i'm looking for, but any improvements would be welcome.
I found that in the module, i can declare a provider method and use it to set any properties i need:
MyModule extends AbstractModule{
...
#Provides #Named("testBean") MyTestBean createTestBean(MembersInjector<TestBean> mi){
TestBean test = new TestBean();
mi.injectMembers(test);
test.setFieldName("aStringValue");
test.setAnotherFieldName(123);
return test;
}
...
}
The good point is that the Provides method replaces the bind() for the bean and this way the actual line count doesn't increase much.
I'm still not 100% sure about any side effects, but it looks promising.
There is a build in mechanism to inject properties.
Properties File:
name=jan
city=hamburg
Module
#Override
protected void configure() {
Names.bindProperties(binder(), properties);
}
then in your bean, just inject by Name
class Customer {
#Inject
#Named("name")
String name;
....
}
There are a couple different ways you could do this, including your way. The only drawback to using a Provider method is that it's essentially a hand-rolled factory that you have to remember to maintain. (And in this specific case, you're also not getting the benefits of constructor injection).
Absent a Provider method, you have to use a binding annotation of some kind. If #Named won't work for you, then you'd need to create an annotation for each binding.
bindConstant().annotatedWith(FieldName.class).to("aStringValue");
public SomeClass {
public void setFieldName(#FieldName String fieldname) {}
}
In some cases this might require a 1-to-1 annotation per primitive/String instance to be bound. But I try to make my annotations somewhat orthogonal to the actual instance being described, preferring instead to use the annotation to describe the relationship between the bound objects and the injection points.
It's not always possible, but a whole group of related primitives could then potentially be described by a single binding annotation, as long as each primitive type is only used once in the set. So, this could hypothetically work:
bindConstant().annotatedWith(MyAnnotation.class).to("aStringValue");
bindConstant().annotatedWith(MyAnnotation.class).to(123);
Parenthetically, I'm curious why you can't used #Named annotations on the property, but you can use them on the injected bean?
Resolution: No I'm no longer extending the original parent.
Original:
Is there a way to annotate an inherited final setter method? I am extending a class which has a final setter which I would like to #Autowire with Spring. The parent class is from a library and cannot be modified.
A workaround I have found is to write a proxy method, but this seems like more work than necessary.
public abstract class SqlMapClientDaoSupport ... {
public final void setSqlMapClient(SqlMapClient smc) {
...
}
}
#Component
public class AccountDao extends SqlMapClientDaoSupport {
// all this just to annotate an existing method?
#Autowire
public final void setSqlMapClientWorkaround(SqlMapClient smc) {
super.setSqlMapClient(smc);
}
}
Edit 1: Above example modified to reflect use case:
The use case is implementing DAO objects for Ibatis/Spring
which extend a common base class. Each DAO needs the same
property set, and each needs to be configured as a bean. I currently
do this by configuring each individually in applicationContext.xml.
<bean id="accountDAO"
class="com.example.proj.dao.h2.AccountDAOImpl"
p:sqlMapClient-ref="sqlMapClient" />
<bean id="companyDAO"
class="com.example.proj.dao.h2.CompanyDAOImpl"
p:sqlMapClient-ref="sqlMapClient" />
<!-- etc... -->
I would prefer to use component-scan to discover and autowire the DAO
objects automatically, which I can't copy/paste botch.
<context:component-scan base-package="com.example.proj.dao.h2" />
I do not see in the annotation guide how one would annotate a
property/member other than where declared. I'm hoping that is
something I'm missing though.
Edit 2: I am no longer extending the SqlMapClientDaoSupport class, instead my AccountDao is a POJO which implements what little functionality was being provided by the Support class. This allows me to use #Autowire at will.
Have you tried configuring it with xml? Because it's an existing class which it looks like you can't change, it's a definite candidate for configuring it with xml. Then you can specify it as autowire", or even configure the property in the xml.
It sounds to me like you shouldn't be trying to set a final field.
There is usually a good reason why fields are final.
Have you setup a SqlMapClientFactoryBean object ?
See here for help
No, there is no way to annotate an inherited final method.
Rather than extend the support class (SqlMapClientDaoSupport) I reimplemented it in my project (it's behavior is minimal) annotating the methods as needed, and my DAO extend that support class.
You could create a new constructor with params for all the setters that are final and #Autowired the constructor, then call the setters in the constructor.