unit test with CDI Unit and EasyMock - unit-testing

I have a project with CDI and I would like to create unit test with mocks.
To manage mocks, I would like to use EasyMock and to run with CDI, I find the cdi-unit project which seem easy to use.
I have a problem to get a mock with EasyMock in CDI context. Here is my unit test:
#RunWith(CdiRunner.class)
#AdditionalClasses(MockFactory.class)
public class ResultYearMServiceImplTest {
#Inject
private IStockDao stockDao;
#Inject
private ResultYearMServiceImpl resultYearMService;
#Test
public void getResultList() {
EasyMock.reset(stockDao);
EasyMock.expect(stockDao.getListStocks()).andReturn(null).once()
.andReturn(new ArrayList<DtoStock>()).once();
EasyMock.replay(stockDao);
}
}
IStockDao needs to be mock in the test, so to get it I would like to use a #Produces method like this (in MockFactory class given to cdi unit by #AdditionalClasses):
#Produces
#ApplicationScoped
public IStockDao getStockDao() {
return EasyMock.createMock(IStockDao.class);
}
When I run my unit test, the mock is good in unit test but I get this error:
java.lang.IllegalArgumentException: Not a mock:
org.jboss.weld.proxies.IStockDao$-1971870620$Proxy$_$$_WeldClientProxy
This one comes because CDI doesn't give an instance of EasyMock IStockDao but a proxified instance and EasyMock doesn't accept this in these methods (like reset method).
So I replace #ApplicationScoped in MockFactory by #Dependent which doesn't proxified the instance but I have a new problem:
This annotation give a new instance of mock at each injection point so I can use it because I have a mock in the unit test to mock method called in the tested class. And this instance of mock must be the same in the tested class (it's not the case with #Dependent).
How can I get the same instance in the unit test and the tested class ?
Thanks.

Needle is your friend for testing CDI.
http://needle.spree.de
public class ResultYearMServiceImplTest {
#Rule
public final NeedleRule needle = new NeedleRule();
#Inject
private IStockDao stockDao;
#ObjectUnderTest
private ResultYearMServiceImpl resultYearMService;
#Test
public void getResultList() {
EasyMock.reset(stockDao);
EasyMock.expect(stockDao.getListStocks()).andReturn(null).once()
.andReturn(new ArrayList<DtoStock>()).once();
EasyMock.replay(stockDao);
}
}

I was unit testing a CDI interceptor with easymock and had the same problem as you.
I would like to share the workaround I used.
It consists in producing the mocks in #Dependent scope. This way we can get over the CDI proxy problem with easymock.
import static org.easymock.EasyMock.createStrictControl;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
/**
* Mock producer. Beans are produced in Dependent scope to not be proxied.
*/
#ApplicationScoped
public class CdiMockProducerUnitTests {
/**
* Mock
*/
private final MyMockClass myMock;
/**
* Constructor creating mocks.
*/
public CdiMockProducerTestesUnitarios() {
myMock = createStrictControl().createMock(MyMockClass.class);
}
/**
* Produces mock in dependent scope.
*
* #return mock
*/
#Produces
#Dependent
public MyMockClass produceMock() {
return myMock;
}
}

The next version of CDI-Unit (2.1.1) adds support for EasyMock in the same way that Mockito is currently supported.

Related

Integration and unit tests with MockMvc

According to the documentation there are two ways to do this:
First:
#RunWith(SpringRunner.class)
#WebAppConfiguration
#ContextConfiguration("my-servlet-context.xml")
public class MyWebTests {
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
// ...
}
This form uses the actual context of the application.
And the second way:
public class MyWebTests {
private MockMvc mockMvc;
#Mock
private MyService myService;
#InjectMocks
private MyController myController;
#Before
public void setup() {
// Process mock annotations
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(myController)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver()).build();
}
#Test
public void testsForPost() throws Exception {
Foo foo = new Foo();
//given
given(myService.findById(Matchers.anyLong())).willReturn(foo);
//when
this.mockMvc.perform((post("/foo")))
//then
.andExpect(status().isMethodNotAllowed())
.andDo(print());
}
...
}
With this method I am not using the application context.
My question is, can I consider the first form as integration tests? And the second as unit tests?
Otherwise what would be the best solution to do unit tests of SpringMVC.
I, too, would consider the first an integration test and the second a unit test.
I think a well written MVC controller should be covered with an integration test and not a unit test. A controller should only orchestrate calls to mappers, services, repositories and the like. Since the mappers, services, repositories and the like should be covered with their own unit tests, you don't gain a lot by unit testing your controller.
An integration test is much more valuable in this case, since it tests the whole interaction between the controller and components it orchestrates. And using tools like DBUnit it is not much harder to write.

Unit testing the obvious

While trying to write test cases for a class whose functionality deals more with boiler plate code than business logic. I started wondering if unit testing is really worth for this class. But then again, when using TDD, we are advised to write test for any piece of logic we add.
As an example the below class, just uses DI to inject dependencies and get config parameters to set up the running of the application. Other than unit testing if dependencies are correctly injected, or if destroy is called when running finishes(which would be unit testing the java CDI framework than my own code), what else I can unit test?
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.inject.Inject;
#Singleton
#Startup
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class PipsAlprConnectionRunner {
#Inject
private PipsAlprConfiguration config;
#Inject
private PipsAlprConnector connector;
#Inject
private Scheduler scheduler;
#Inject
#PipsAlprAdapterService
private ServiceStatus status;
private Timer connectorTimer = null;
#PostConstruct
public void initialized() {
status.started();
connectorTimer = scheduler.schedule(connector, 0,
1000 * config.getPollPeriodSeconds());
status.operational();
}
#PreDestroy
public void destroy() {
connectorTimer.cancel();
connector.shutdown();
status.stopped();
}
}
I was unable to think of any testing scenarios to utilize TDD, on the above class, so just came up with the code, and now i am wondering what exactly can i unit test here.
Well, a case can be made that the class does something. It changes a status, it starts a timer. You can inject mocks of these objects into the class via Mockito and then make sure, that initialized() and destroy() both do what you expect them to do to these mocks.
#RunWith(MockitoJUnitRunner.class)
public class PipsAlprConnectionRunner {
#Mock
private PipsAlprConfiguration config;
#Mock
private PipsAlprConnector connector;
#Mock
private Scheduler scheduler;
#Mock
private ServiceStatus status;
#InjectMocks
private PipsAlprConnectionRunner pipsAlprConnectionRunner ;
#Test
public void initialized_should_set_status_started() {
pipsAlprConnectionRunner.initialized();
Mockito.verify(status).started();
}
// etc.
}
It's pretty much a question of personal taste if you want to create one method per "point of failure" or one method per method/test.
Personally, I would say that the goal is 100% coverage, so even pretty simple classes that mainly delegate should be covered. What happens if someone changes anything? The test ensures that such changes will not break existing functionality.

Mock final class and inject it to autowired data member and overcome postConstruct method call

I want to unit test a java class with an autowired final class object, as well as another autowired class that has #PostConstruct method. While it is possible to test them individually, i am not able to combine them together.
This question is an extension to the question on injecting mockito mocks into spring bean
Code to be tested
public class A {
#Autowired
private FinalClass serviceClient;
#Autowired
private ClassWithPostConstructor resourceVerifier;
//no setters or constructors
public String useBothFinalClassAndClassWithPostConstructor() {
//logic to be tested
}
}
Working Test class
#RunWith(PowerMockRunner.class)
#PrepareForTest(FinalClass.class)
public class ATest {
//#org.mockito.Mock //fails to mock final class
#org.powermock.api.easymock.annotation.Mock
private FinalClass serviceClient;
#org.powermock.api.easymock.annotation.Mock
private ClassWithPostConstructor resourceVerifier;
//other mock objects required for mocking the services
//#InjectMocks //fails since mocking final class
private A a;
#Before
public void init() {
a = new A();
//working snippet with setters created in A and without #Autowired here within the test
serviceClient = PowerMock.create(FinalClass.class);
a.setServiceClient(serviceClient);
resourceVerifier = PowerMock.create(ClassWithPostConstructor.class);
a.setClassWithPostConstructor(resourceVerifier);
}
#Test
public void testTheMethodUsingExpectAndVerify() {
//test the functionality here
EasyMock.expect(serviceClient.callService()).andReturn("someMock");
EasyMock.expect(resourceVerifier.verifyFn()).andReturn("success");
PowerMock.replayAll();
A.useBothFinalClassAndClassWithPostConstructor();
PowerMock.verifyAll();
}
}
The above code works with the need for setters in file
Expected Test class
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"file:spring-configuration/unit-testing-config.xml"})
#PrepareForTest(FinalClass.class)
public class ATest {
#Autowired
private FinalClass serviceClient;
#Autowired
private ClassWithPostConstructor resourceVerifier;
//other mock objects required for mocking the services
private A a;
#Before
public void init() {
a = new A();
}
#Test
public void testTheMethodUsingExpectAndVerify() {
//test the functions here
EasyMock.expect(serviceClient.callService()).andReturn("someMock");
EasyMock.expect(resourceVerifier.verifyFn()).andReturn("success");
PowerMock.replayAll();
A.useBothFinalClassAndClassWithPostConstructor();
PowerMock.verifyAll();
}
}
//spring-configuration/unit-testing-config.xml
//same error even on customer factory
<bean id="resourceVerifier" class="org.powermock.api.easymock.PowerMock" factory-method="createMock">
<constructor-arg type="java.lang.Class" value="com.company...resourceVerifier" />
</bean>
<bean id="resourceVerifier" class="org.powermock.api.easymock.PowerMock" factory-method="createMock">
<constructor-arg type="java.lang.Class" value="com.company...serviceClient" />
</bean>
The above snippet mocks finalClass but calls #PostConstructor of ResourceVerifier.class - What should be done here to overcome this call.
Investigations
It is possible to test autowired files using #InjectMocks without the need for spring context configurations.
#InjectMock fails silently for static and final fields and when failing, it doesn't inject other mocks as well.
It is possible to mock final class using PowerMock's createMock and run the test with PowerMockRunner and #PrepareForTest. But this requires new unnecessary setters to inject the mocks for #Autowired fields.
MockitoAnnotations.#Mock doesn't work along well with PowerMock (especially when mocking final class objects) and can be solved via EasyMock.Annotations.#Mock
EasyMock and PowerMock doesn't have an #InjectMocks annotation to inject the mocks as possible by Mockito (Would have solved the problem in secs).
It is possible to inject autowired spring beans via SpringJUnit4Runner and a separate unit-testing #ContextConfiguration
It is possible to run the same test file with both PowerMockRunner and SpringJUnit4Runner with PowerMockRunnerDelegate
I know that #PostConstruct method will not be executed automatically if mocked in code than by using spring bean creation and injection.
If a wrapper factory bean class is written and used to create the mocks, it injects automatically, but calls the #PostConstruct method as well along with it.
It is not possible to depend on Springockito since it is unreliable at this stage.
But none of these worked since the usecase is a combination of all these.
Possible Solutions
Remove #Autowired fields and use Setter injections so that it is possible by mocking normally using PowerMock(Tested to work) - But it is a convention followed by external team packages - i should try my best to stick to it.
Or set #Autowired to the setters or to constructor
Alternatives?
I don't feel that the classes require reorganisation as they serve their purposes and are well designed as well.
Any other means that doesn't require to keep hands on the class under test - What if i didn't have the permissions to modify this class? i.e., a pure testing library dependent solution.
Not sure whether it is possible by PowerMockito? Haven't tried the combination of PowerMockito with PowerMock.
Hmm,
Not sure whether it is possible by PowerMockito? Haven't tried the combination of PowerMockito with PowerMock.
Seems to me you have a mess in your head and misunderstanding PowerMock/Mockito and EasyMock.
You should never use at same time PowerMockito and PowerMock, because these two classes are PowerMock friendly API for two different mocking frameworks: EasyMock and Mockito. And there is no reason to use they both.
And of course this want work
//#org.mockito.Mock //fails to mock final class
#org.powermock.api.easymock.annotation.Mock
private FinalClass serviceClient;
#org.powermock.api.easymock.annotation.Mock
private ClassWithPostConstructor resourceVerifier;
//other mock objects required for mocking the services
//#InjectMocks //fails since mocking final class
private A a;
Because, you decelerate and create mocks via EasyMock API, but tries to inject it with Mockito Annotation.
You have to choose only one Mocking Framework and use suitable API for it. For now, Mockito + PowerMockito (PowerMock API for Mockito) better fit your requirements.
You may full example how it works on PowerMock github
#RunWith(PowerMockRunner.class)
#PrepareForTest(FinalClass.class)
public class SpringInjectFinalClassExampleTest {
#Mock
private FinalClass finalClass;
#InjectMocks
private MyBean myBean = new MyBean();;
#Test
public void testInjectFinalClass() {
final String value = "What's up?";
when(finalClass.sayHello()).thenReturn(value);
assertEquals(value, myBean.sayHello());
}
}

Grails integration tests with multiple services

What is the best practice to test a Grails Service which depends on another Service?
The default mixin TestFor correctly inject the service under test, for eg:
#TestFor(TopService)
class TopServiceTests {
#Test
void testMethod() {
service.method()
}
}
but if my instance of TopService (service) relies on another Service, like InnerService:
class TopService {
def innerService
}
innerService will not be available, dependency injection doesn't seem to fill this variable. How should I proceed?
Integration tests should not use the #TestFor annotation, they should extend GroovyTestCase. The test annotations are only for unit tests (and will have bad behavior when used in integration tests, especially the #Mock annotations). You're seeing one of those bad behaviors now.
If you extend GroovyTestCase you can then just have
def topService
At the top of your test and it'll get injected with all of it's dependencies injected.
For a unit test case, you'd just want to add new instances of associated services to your service in a setUp method. Just like:
#TestFor(TopService)
class TopServiceTests {
#Before public void setUp() {
service.otherService = new OtherService()
}
...
I have a CustomerRegistrationServiceTest and my CustomerRegistrationService depends on the PasswordService.
my CustomerRegistrationService just autowires it like normal:
class CustomerRegistrationService {
def passwordService
In my CustomerRegistrationServiceTest I have:
#TestFor(CustomerRegistrationService)
#Mock(Customer)
class CustomerRegistrationServiceTests extends GrailsUnitTestMixin {
void setUp() {
mockService(PasswordService)
}
So when I test the CustomerRegistrationService, it is able to access the PasswordService

How do I use PowerMock / Mockito / EasyMock to use a mocked object for dependency injection?

I have an AuthenticationManager.authenticate(username,password) method that gets called in someMethod of a SomeService under test. The AuthenticationManager is injected into SomeService:
#Component
public class SomeService {
#Inject
private AuthenticationManager authenticationManager;
public void someMethod() {
authenticationManager.authenticate(username, password);
// do more stuff that I want to test
}
}
Now for the unit test I need the authenticate method to just pretend it worked correctly, in my case do nothing, so I can test if the method itself does the expected work (Authentication is tested elsewhere according to the unit testing principles, however authenticate needs to be called inside that method) So I am thinking, I need SomeService to use a mocked AuthenticationManager that will just return and do nothing else when authenticate() gets called by someMethod().
How do I do that with PowerMock (or EasyMock / Mockito, which are part of PowerMock)?
With Mockito you could just do that with this piece of code (using JUnit) :
#RunWith(MockitoJUnitRunner.class)
class SomeServiceTest {
#Mock AuthenitcationManager authenticationManager;
#InjectMocks SomeService testedService;
#Test public void the_expected_behavior() {
// given
// nothing, mock is already injected and won't do anything anyway
// or maybe set the username
// when
testService.someMethod
// then
verify(authenticationManager).authenticate(eq("user"), anyString())
}
}
And voila. If you want to have specific behavior, just use the stubbing syntax; see the documentation there.
Also please note that I used BDD keywords, which is a neat way to work / design your test and code while practicing Test Driven Development.
Hope that helps.