How to mock services with Arquillian? - java

Is it possible to use some kind of mocking framework with Arquillian, or precisely how to mock injected EJBs? I know that, with using the CDI (Contexts and Dependency Injection), it is possible to inject alternatives in test. But without CDI as injection mechanism, when I'm only using EJB injection, how this is possible?
Recently I have tested my EJBs with service interface mock implementation as following:
// Service inteface
public interface Audit {
void audit(String info);
}
// Mock implementation
#Stateless
public class MockAuditBean implements Audit {
public static String lastInfo = null;
#Override
public void audit(String info) {
this.lastInfo = info;
}
}
// assert in test
assertTrue(MockAuditBean.lastInfo.contains("dummy"));
This approach is possible but requires a lot of custom mock implementations. What is worse, injected instances of mocks are proxies and uses service interface. These can not be cast to mock implementation class to compare results. Only static members and methods of mock implementation can be used.
I have tested also another possibilities to set related EJBs manually. This approach has several draw-backs. It requires that target EJB of test has non-private members or setters for them. When target EJB relies on #PostConstruct lifecycle annotation, you have to call it after your manual "injection" setting.
Advantage of this solution is the ability to use mock frameworks, like mockito or jMock.
Have someone an experience to share, how to test and set-up such integration test, or even use mocking frameworks in it ?

IMO, EJBs where not designed with testing in mind. Your alternative sounds like a good enough compromise and I'd go for it. Using mockito is a major plus and I use it even when working with CDI.
I'd use the "default" member scope and javadoc to other developers access them for testing purposes only.

This article from Oracle shows an approach to "injecting" an EJB for testing using JUnit and Mockito:
http://www.oracle.com/technetwork/articles/java/unittesting-455385.html
Edit:
Basically the inclusion of Mockito allows for mocking objects like EntityManager etc.:
import static org.mockito.Mockito.*;
...
em = mock(EntityManager.class);
They show the approach for EJB as well using mockito. Given an EJB:
#Stateless
public class MyResource {
#Inject
Instance<Consultant> company;
#Inject
Event<Result> eventListener;
The test can "inject" those objects:
public class MyResourceTest {
private MyResource myr;
#Before
public void initializeDependencies(){
this.myr = new MyResource();
this.myr.company = mock(Instance.class);
this.myr.eventListener = mock(Event.class);
}
Note that MyResource and MyResource are in the same class path but different source folders so your tests have access to the protected fields, company and eventListener.
Edit:
Note: you can use FacesMockitoRunner from JBoss (https://community.jboss.org/thread/170800) to get this done for the common JSF components and use annotations for the others (Java EE 6 with CDI enabled as a pre-requisite for this, but does not require JBoss server):
Include jsf, mockito, and jsf-mockito dependencies in maven:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.test-jsf</groupId>
<artifactId>jsf-mockito</artifactId>
<version>1.1.7-SNAPSHOT</version>
<scope>test</scope>
</dependency>
Add the #RunWith annotation to your test:
#RunWith(FacesMockitoRunner.class)
public class MyTest {
Inject common Faces objects using annotations:
#Inject
FacesContext facesContext;
#Inject
ExternalContext ext;
#Inject
HttpServletRequest request;
Mock any other objects using the annotations #org.mockito.Mock (it appears FacesMockitoRunner calls this behind the scenes so it may not be necessary here):
#Mock MyUserService userService;
#Mock MyFacesBroker broker;
#Mock MyUser user;
Init the Injected Mocks using the
#Before public void initMocks() {
// Init the mocks from above
MockitoAnnotations.initMocks(this);
}
Setup your test as usual:
assertSame(FacesContext.getCurrentInstance(), facesContext);
when(ext.getSessionMap()).thenReturn(session);
assertSame(FacesContext.getCurrentInstance().getExternalContext(), ext);
assertSame(FacesContext.getCurrentInstance().getExternalContext().getSessionMap(), ext.getSessionMap());
etc.

You may want to take a look at testfun-JEE which allows you to unit-test (not integration-test) your EJBs outside of a container.
testfun-JEE takes care for injecting EJBs as well as EntityManager and some standard resource directly into your test class - references within these EJBs to other EJBs are resolved automatically.
And the coolest thing is that you can mock any dependency by simple adding a member variable to your test annotated with #Mock - testfun-JEE will inject this mock wherever needed.
See examples in https://github.com/michaelyaakoby/testfun.
BTW, while this framework was published very recently (like today...) it is being widely used for over a year in my company.

Work with a framework, like Mockito.
Unfortunately, Arquillian does not automatically include the necessary dependencies.
You can add them in your #Deployment function:
#Deployment
public static WebArchive deploy()
{
return ShrinkWrap.create(WebArchive.class)
.addAsLibraries( // add maven resolve artifacts to the deployment
DependencyResolvers.use(MavenDependencyResolver.class)
.artifact("org.mockito:mockito-all:1.8.3")
.resolveAs(GenericArchive.class))
);
}
source
Then in your #Test method you could use:
mock(MockedService.class).methodName()
This github showcase shows a way to allow auto discovery, which seems to require some setup:
source

If you really want to interact with mocks in your integration tests (for instance one reason might be that you don't have a full blown implementation yet or you have an facade to external systems which you don't have control over), there is quite an easy way to integrate Mockito with your Arquillian tests, have a look at this example from the showcase. It's actually extension on its own, but not released as one.

Related

Dagger2: How to use #Inject in a JUnit test?

I would like to have the ability to inject dependencies into JUnit tests with Dagger 2 (I'm new to this framework). Coming from Spring, there you can do something like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = MyApplication.class)
public class MyTestClass {
#Autowired
private MyService service;
#Test
public void testMySerivce() { /* ... */ }
}
... but with Dagger 2 I have not yet found a solution that does not rely on an explicit DaggerMyComponent.builder().build().myService().
Ideally, I would imagine the solution to look something like the following:
// tell JUnit that dagger needs to do some post processing
#RunWith(DaggerJUnit4Runner.class)
// tell dagger which component classes to use for injection
#Components(MyComponent.class)
public class MyTestClass {
#Inject
private MyService service;
#Test
public void testMySerivce() { /* ... */ }
}
Unfortunately, there is no DaggerJunit4Runner.
Any hints on how this could be accomplished would be greatly appreciated.
I haven't seen any built-in feature for this, or any prominent testing library that supports this.
Dagger does all its dependency wiring at compile time, and only in ways you tell it to; unlike Spring, there's no code written to read a testing class at runtime or supply the dependencies it needs. Dagger's appeal over Guice and Spring comes from compile-time compilation, validation, and optimization. Though what you describe would be very useful, that kind of reflection is antithetical to Dagger's original motivations. Either your Dagger component is compiled with the generated code to inject the test, or you need to be able to pull those dependencies out independently as you've listed above.
For unit tests you'll probably need to skip Dagger and create your classes or their mocks manually; for system or integration tests, you'll need to expose all of the classes you need on the component definition. If you want to replace dependencies with test doubles for repeatability or isolation, you'll need to make your component sufficiently configurable to accept the replacement implementations, or you'll need to create a new for-testing Component implementation that uses the test doubles instead of the real implementations.

Integration Tests with PowerMock and Spring Boot

I'm doing some integration tests, on a Spring Boot application.
Usually the integration tests that I was used to develop, was regarding the application domain, without any external service involved.
Since this time I need to make an integration test on a service which uses both a database and an external service called by an SDK, I've tried doing something like the following:
#RunWith(PowerMockRunner::class)
#SpringBootTest
#PowerMockRunnerDelegate(SpringRunner::class)
#PrepareForTest(McpProductService::class)
class MyServiceIntegration {
#Mock
private ExternalService externalService;
#Autowired
#InjectMocks
private MyServiceImpl myService;
#Test
public void thisTestShouldWork() {
...
}
}
What is confusing me is: how should I declare myService attribute? Usually when I use Mockito + PowerMock in my Unit Tests, I usually test the implementation, not the whole Service Interface + Spring Injection. But I can't use #Autowired if I'm using just it's implementation, not the Interface.
Is there any best practice for this issue that I'm facing?
Disclaimer: I'm assuming that what you are after is an end-to-end test of a service interface, backed by multiple classes. I assume (and hope) that you don't have a single class handling both database and webservice integration.
I don't see the need to use PowerMock here, it is usually something one would use for testing legacy code with a lot of static stuff. If you are using Spring boot, your code should be of a quality that makes PowerMock unnecessary.
When writing an end-to-end test, the principles are the same as a per-class unit test, only with a larger scope:
With a unit test, you create an instance of the class under test, and mock all its external dependencies (other classes)
With an end-to-end test, you create an "instance" of your module under test, and mock its external dependencies.
So, here you should find a mechanism to mock the parts of your code that communicates with external sources, like web service clients, database classes (if you don't use an in-memory db for your test (you should)). This will typically be a Spring config that is almost identical to the one used in production, but with said parts mocked out. Then, you just #Inject the parts you need to communicate with in order to complete the test.
Assuming that you use component scan and annotations for all beans, you could mock the endpoint-classes and use profiles:
This code is based on memory only, might not work on copy-paste, but hopefully you could use the concepts..
#Profile("test")
#Configuration
public class TestConfiguration {
#Bean
#Primary
public SomeWebserviceClient someWebserviceClient() {
return mock(SomeWebserviceClient.class);
}
}
Production code:
#Service
public class SomeClass {
#Inject
private SomeWebserviceClient client;
}
Then in the test:
#RunWith(PowerMockRunner::class)
#SpringBootTest
#ActiveProfiles("test")
public class SomeTest {
#Inject
private SomeClass someClass;
#Inject
private SomeWebserviceClient client; //<< will inject mock
}
Mock will also be injected into SomeClass

Correct way to Integrate JAX-RS with CDI?

I used to integrate Service and DAO beans in Jersey REST resources by annotating them with #Path following Java EE tutorial
In general, for JAX-RS to work with enterprise beans, you need to annotate the class of a bean with #Path to convert it to a root resource class. You can use the #Path annotation with stateless session beans and singleton POJO beans.
So my code used to be something like this:
#Path("/")
public class ServiceResource {
#Inject
private AccountService accountService;
#GET
#Path("/account/get")
public Account getAccount(#QueryParam("id") String id) {
return accountService.get(id);
}
}
#javax.inject.Singleton
#Path("")
public class AccountService {
public Account get(String id){...}
}
Now, I started integrating a Quartz Job into my application, and I wanted to find a way to inject my AccountService inside a job like this
public class AccountJob implements Job {
#Inject
private AccountService accountService;
#Override
public void execute(JobExecutionContext jec) throws JobExecutionException {
accountService.updateAllAccounts();
}
}
I found this answer that tells to use DeltaSpike to do the Job, so I added the following dependencies to my pom.xml, and without adding any more lines of code to any class the inejection of accountService to my Job works fine
<dependency>
<groupId>org.apache.deltaspike.modules</groupId>
<artifactId>deltaspike-scheduler-module-api</artifactId>
<version>1.7.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.modules</groupId>
<artifactId>deltaspike-scheduler-module-impl</artifactId>
<version>1.7.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.cdictrl</groupId>
<artifactId>deltaspike-cdictrl-api</artifactId>
<version>1.7.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.deltaspike.cdictrl</groupId>
<artifactId>deltaspike-cdictrl-weld</artifactId>
<version>1.7.2</version>
<scope>runtime</scope>
</dependency>
However, I realized that when I remove the #Path("") from AccountService, its instance is still injected fine inside ServiceResource, so my questions are the following:
Why adding DeltaSpike dependencies made it possible to inject my beans without using #Path on them?
By searching more, I understood that DeltaSpike internally uses Weld to do the injection, and since I am already using GlassFish 4.0, I know that Weld is already there, so why the injection is not working by default in my Job class and in ServiceResource class without adding #Path on my beans? Actually why adding #Path is even suggested in the Java tutorial?
Is there any bad side effects that I don't see in my code, because I think that I am mixing multiple DI methods here without really understanding how do they work?
Update: After more search, I realize that Jersey doesn't use Weld for dependency injection, instead it uses HK2, a different framework that also happens to be a part of GlassFish, when I try to inject AccountService without using #Path it shows the following exception
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=AccountService,parent=ServiceResource,qualifiers={}...
So this updates the questions to the following:
How to make HK2 injections works? // Without using #Path as mentioned in the Java EE Tutorial
If I managed to to do DI with HK2, will it be safe to use DeltaSpike to do DI for the Quartz Job? Is it okay to mix two CDI framewroks together to scan the classes and do the injection?
I put my my source code on pastebin; pom.xml is here and the Java is here
You do not need to set the Path annotation on your AccountService CDI bean. If CDI is enabled on your application (either with empty beans.xml in CDI 1.0 or discovery-mode=all in CDI > 1.0), you can #Inject any CDI bean in your JAX-RS resource.
So you just have to write the following class:
#Path("/")
public class ServiceResource {
#Inject
private AccountService accountService;
#GET
#Path("/account/get")
public Account getAccount(#QueryParam("id") String id) {
return accountService.get(id);
}
}
#javax.inject.Singleton
public class AccountService {
public void Account get(String id){...}
}
The article you linked in your post deals with mixing EJB and CDI annotations. For example you can mix #Stateless and #Path annotations. It's interesting for example because you can :
Benefit of EJB transaction in your Rest resource (even if now you can use #Transactional interceptor binding)
Set a pool of resources
etc.
Note that all of this works without the help of deltaspike dependency.
For your second question, as Quartz manages its own threads, classes are not handled by CDI so you can not inject beans in Quartz classes. The aim of the deltaspike module is to allow injecting CDI beans in Quartz Jobs. Internally, deltaspike controls CDI Contexts.
EDIT
For your last questions:
Your HK2 problem comes pretty sure from a missing dependency (in your application or server). As said in a previous comment, I managed to deploy your App on Glassfish 4 (build 89) with the source files you provided.
Regarding the integration of CDI with Quartz, I think the best is to implement your own JobFactory and instanciate your jobs using BeanManager. Take a look at this link : https://devsoap.com/injecting-cdi-managed-beans-into-quarz-jobs/
First of all injected resources(beans) and Jersey Endpoint class(point of injection) must be CDI-Aware. It must be detecteable by CDI. We can use bean-discovery-mode="all" - then CDI scan ALL classes or
bean-discovery-mode="annotated" and MARK our class with PROPER annotation: from here : Bean defining annotations. I prefer#Dependent or #RequestScoped
Then we must use Jersey Extension
<dependency>
<groupId>org.glassfish.jersey.ext.cdi</groupId>
<artifactId>jersey-cdi1x-servlet</artifactId>
<version>{version}</version>
<scope>runtime</scope>
</dependency>
`
to connect CDI with HK2 discovery mechanism.
Here is Official oracle Guideline
The default beans.xml discovery-mode (in Java EE 7) is "annotated". Which means only beans that have CDI annotations are recognized and managed by CDI.
Your AccountJob class is not annotated. If you want CDI to be able to inject the service into it then you need to annotate it with some scope annotation, e.g. #ApplicationScoped.
Your other option is to create CDI producer for creating AccountJob beans. See:
http://docs.jboss.org/weld/reference/latest/en-US/html_single/#_producer_methods

Using a Class with a #Required Field in Unit Test with Mockito

I'm trying to unit test a class; for the sake of brevity we'll call it Apple. It has a #Required setter that takes an AppleManager bean. AppleManager itself has a #Required setter than takes an AppleStorageClient bean. I am mocking AppleManager and injecting it into Apple, but I also need to use the real AppleManager class to retrieve data using methods from its AppleStorageClient object. How can I achieve this with Spring/Mockito?
Test:
public class AppleTest {
#InjectMocks
private Apple apple;
#Mock
private AppleManager appleManager;
?????
private AppleManager realAppleManager;
//I tried = new AppleManager() here but the object is null...
//ostensibly because Spring doesn't know I want to use the bean
//also tried #Autowired to no avail
#Before
public void doBeforeStuff() {
MockitoAnnotations.initMocks(this);
}
...
}
Source:
public class Apple {
private AppleManager appleManager;
#Required
public void setAppleManager(AppleManager appleManager) {
this.appleManager = appleManager;
}
....
}
&
public class AppleManager {
private AppleStorageClient appleStorageClient;
#Required
public void setAppleStorageClient() {
this.appleStorageClient = appleStorageClient;
}
...
}
In general it looks like something is 'uncomplete' here. I'll explain why.
Technically If you're using spring - it doesn't sound like a unit test to me anymore, probably integration test or something.
Unit tests are in general should be really-really fast and starting up spring won't let them pass fast enough (think about having thousands of unit tests in your project each of them running spring on startup - it will take them ages to complete).
But let's say its only about definitions. When you're using spring testing framework with JUnit, someone has to start and maintain a spring context to do all the Dependency Injection magic and apply it to the test case.
In Junit implementation a special Runner (a JUnit abstraction) is required:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:my-test-context.xml" }) // or use Java Config
This doesn't appear in the question though.
So now Spring will create a context and will attempt to inject beans. And we have effectively reduced our issue to the issue of having two implementations of the interface and asking spring to inject implementation by interface so that two different implementations will be injected. There are 2 solutions I can see here:
Create a Mock outside spring - you probably won't specify your expectations in spring anyway. Maintain only a "real apple manager" in spring
Maintain both in spring but in your test case use a #Qualifier annotation
Now what I would like to emphasize is that if you maintain real apple manager that contacts "apple store" (probably a database, with driver support, transaction management and so forth) you'll have to create a test context so that it will be able to connect to that database, and if the apple manager internally injects its dependencies via spring, then these beans are also have to be specified.
So that if in future you'll change something in the underlying store (say, add a dependency in a driver to another spring bean, this test context will automatically become broken). Just be aware of this and inject beans wisely.

How to mock annotated EJBs?

I googled it already, but seems kinda hard to find topics on mocking dependency injected objects (EJB 3.0).
public class MyTestBean
{
#EJB
ILoginService mLoginService;
public void doLogin() {
if (!mLoginService.login(name, pass)) {
// fehler
}
}
When running tests with openEJB I want to have that LoginService.login(name, pass) return true. Is there a way to mock the LoginService bean?
(Currently the login-methode uses some JAAS-stuff i can't emulate during tests.)
May be have a look at Mockito. You can the apply #EJB annotation on a setter and inject mocked LoginService in your tests.
Another option is to simply provide a second implementation of your ILoginService interface. This second implementation is the mock, but no special Mock library or support is necessary for this.
You put this implementation is a special source folder, typically called test. Then you build your deployment scripts so that for normal builds this test folder is ignored. When you do your unit tests and build the archive for testing, you explicitly include the Mock implementation from the test source folder.

Categories