Background:
According to this issue http://java.net/jira/browse/JERSEY-623, InMemoryTestContainer won't be able to support resource with injectable constructor. So if you have, say, HttpServletRequest injected in your resource class, you will need other test containers, such as grizzly.
My case:
I am using dropwizard which is running Jersey underneath, I have HttpServletRequest injected in my resource class like this:
#Context HttpServletRequest request;
my test class looks like:
import com.yammer.dropwizard.testing.ResourceTest;
public class MyResourceTest extends ResourceTest {
// all the tests go here
}
Question:
How to switch the test container from InMemoryTestContainer to grizzly?
I've not had to do this myself, but this gist might be of some help.
The relevant parts are the use of
new JerseyTest(new GrizzlyWebTestContainerFactory())
and the inclusion of
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-grizzly2</artifactId>
<version>1.12</version>
</dependency>
In the pom.xml.
Related
I want to mock a static method in JUnit 5. But unfortunately, JUnit 5 doesn’t support Mockito. Is there another method to achieve the same other than reverting back to JUnit 4?
From Mockito 3.4.0 (2020-07-10), it is possible to mock static methods out of the box even in JUnit 5, without any extension.
In the documentation, you can find an example: 48. Mocking static methods (since 3.4.0)
Important note: You need to use inline mock maker. So the dependency to use is not the core one:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.4.6</version>
<scope>test</scope>
</dependency>
Example:
Class under test:
package teststatics;
public class FooWithStatics {
public static Long noParameters() {
return System.currentTimeMillis();
}
public static String oneParameter(String param1) {
return param1.toUpperCase();
}
}
Test class:
package teststatics;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
public class FooWithStaticsTest {
#Test
void testStatic() {
// Before mock scope, usual behavior.
assertNotEquals(0L, FooWithStatics.noParameters());
assertNotEquals("yyy", FooWithStatics.oneParameter("xxx"));
// Mock scope
try (MockedStatic mocked = mockStatic(FooWithStatics.class)) {
// Mocking
mocked.when(FooWithStatics::noParameters).thenReturn(0L);
mocked.when(() -> FooWithStatics.oneParameter("xxx")).thenReturn("yyy");
// Mocked behavior
assertEquals(0L, FooWithStatics.noParameters());
assertEquals("yyy", FooWithStatics.oneParameter("xxx"));
// Verifying mocks.
mocked.verify(times(1), FooWithStatics::noParameters);
mocked.verify(times(1), () -> FooWithStatics.oneParameter("xxx"));
}
// After mock scope returns to usual behavior.
assertNotEquals(0L, FooWithStatics.noParameters());
assertNotEquals("yyy", FooWithStatics.oneParameter("xxx"));
}
}
The short answer is no, as the Mockito team is done with their work and is waiting for the JUnit team for an extension and are discussing here a lot.
With some overhead you can: As JUnit 5 provides support for running legacy JUnit 4, and there you can use Mockito. So you can create tests in Junit4 for these cases:
A sample project for migration setup with gradle and with mvn. From there I am using PowerMock 2.0 beta with Mockito 2.
The reason why Mockito doesn't provide static methods mocking at the moment is because of the common belief that static method shouldn't need to be mocked.
However, there is an open item for Mockito here that discusses the issue.
While this doesn't answer your question, in general it tells you why you shouldn't need the feature at all or will allow you to join the conversation with your ideas.
Make sure to have mockito-inline dependency in your POM file
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.6.28</version>
<scope>test</scope>
</dependency>
In my case I had to test scenario where exception thrown static method encode() of URLEncoder Class, so for that
try (MockedStatic theMock = mockStatic(URLEncoder.class)) {
theMock.when(() -> URLEncoder.encode("Test/11", StandardCharsets.UTF_8.toString()))
.thenThrow(UnsupportedEncodingException.class);
when(restClient.retrieveByName("Test%2F11")).thenReturn(null);
Assertions.assertThrows(ResponseStatusException.class, ()->service.retrieveByName("Test/11"));
}
We can mock a static method by JMockit.
JMockit is used for mocking the external dependencies outside the test boundary, similar to Mockito and other such mocking libraries.
The most important feature of JMockit is that it lets us mock anything, even the things that are hard to mock with other libraries such as constructors, static and final methods. It even allows mocking the member fields and initialization blocks as well.
Follow the below steps to enable JMockit:
The JMockit artifact is located in the central Maven repository, add the JMockit dependency in pom.xml
<!-- https://mvnrepository.com/artifact/org.jmockit/jmockit -->
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.49</version>
<scope>test</scope>
</dependency>
Mock the Class method in TestClass:
public class TestClass{
#Test
public void testMethod() {
new MockUp<ClassName>(){
#Mock
//mock the method here
};
}
}
Follow the tutorial to know more about how to use the JMockit.
In order to get code coverage report, i instrument the #Decorator bean by cobertura maven plugin.
When running my unit test in OpenEJB container. The container reports some error during start up (new initial context).
Caused by: org.apache.webbeans.exception.WebBeansConfigurationException: Decorator : MyDecorator, Name:null, WebBeans Type:DECORATOR, API Types:[org.apache.commo
ns.configuration.Configuration,net.sourceforge.cobertura.coveragedata.HasBeenInstrumented,org.apache.commons.configuration.AbstractConfiguration,MyDecorator,org.apache.commons.configuration.event.EventSource,java.lang.Object], Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.Default] delegate at
tribute must implement all of the decorator decorated types, but decorator type interface net.sourceforge.cobertura.coveragedata.HasBeenInstrumented is not assignable from deleg
ate type of interface org.apache.commons.configuration.Configuration
Details:
I have one Decorator to be unit tested.
Something like
import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.commons.configuration.Configuration;
#Decorator
public class MyDecorator extends AbstractConfiguration {
#Inject
#Delegate
private Configuration conf;
.....
}
After cobertura instrumented it, the code is like below:(I uncompile it)
import net.sourceforge.cobertura.coveragedata.HasBeenInstrumented;
#Decorator
public class MyDecorator extends AbstractConfiguration
implements HasBeenInstrumented
{
#Inject
#Delegate
private Configuration conf;
.....
}
As you can see, cobertura add one more interface for my decorator.
When OpenEJB load and deploy this instrumented class, a error is reported:
Caused by: org.apache.webbeans.exception.WebBeansConfigurationException: Decorator : MyDecorator, Name:null, WebBeans Type:DECORATOR, API Types:[org.apache.commo
ns.configuration.Configuration,net.sourceforge.cobertura.coveragedata.HasBeenInstrumented,org.apache.commons.configuration.AbstractConfiguration,MyDecorator,org.apache.commons.configuration.event.EventSource,java.lang.Object], Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.Default] delegate at
tribute must implement all of the decorator decorated types, but decorator type interface net.sourceforge.cobertura.coveragedata.HasBeenInstrumented is not assignable from deleg
ate type of interface org.apache.commons.configuration.Configuration
The error log say that the #Decorator and the #Delegate should implement the same types.
But after instrument, the to be tested class has one more interface.
Then i try to instrument the org.apache.commons.configuration.AbstractConfiguration and org.apache.commons.configuration.Configuration. (by instrument the commons-configuration-1.9.jar by cobertura command line)
And modify my code like:
#Decorator
public class MyDecorator extends AbstractConfiguration {
#Inject
#Delegate
private AbstractConfiguration conf;
.....
}
//I use AbstractConfiguration instead of Configuration, because the Configuration is an //interface which could not be instrumented.
After all of this,the problem is solved.
But it is not a good way to do this.
The root cause is maven cobertura plugin identify the class file is instrumented by adding an interface to the original class, i works for most of the cases.
But not for a #Decorator bean which running in an container.
Should i create an comments for maven-cobertura-plugin org?
Any one has some suggestion on how to unit test #Decorators.And easy to get coverage report?
May be my unit test is not implement in the good way, maybe the openejb is not good for this?
Normally how do you unit test your #Decorators?
Cobertura does not instrument interfaces. It is recommended the non-instrumented classes go in the classpath after the instrumented classes for that reason.
So when instrumenting, compile first with maven normally, then place yourself in the directory where the sourcecode of the classes you want to instrument exists, and then run the following command : mvn cobertura:instrument.
This will make cobertura instrument all the classes, and maven will automatically add the files not instrumented. the instrumented code will be at ".\target\generated-classes\cobertura".
You'll need to run the 'jar -cvf [name-of-jar].jar *', then you'll get your instrumented jar.
How can I unit test the ProcessorBean?
Since I only wan't to test the ProcessorBean and not the Dao, I need to stub or mock the Dao, but I have no idea how I could do that with Junit.
I'm using Junit4 and Ejb3.0
#Stateless
public class ProcessorBean {
#EJB
private Dao dao;
public void process() {
//logic to be tested
}
}
There's some support in OpenEJB you might find useful in combination with mocking.
As an alternative to the EJB 3.0 Embedded EJBContainer API, you can simply build your app up in code.
import junit.framework.TestCase;
import org.apache.openejb.jee.EjbJar;
import org.apache.openejb.jee.StatelessBean;
import org.apache.openejb.junit.ApplicationComposer;
import org.apache.openejb.junit.Module;
import org.junit.Test;
import org.junit.runner.RunWith;
import javax.ejb.EJB;
#RunWith(ApplicationComposer.class)
public class ProcessorBeanTest extends TestCase {
#EJB
private ProcessorBean processorBean;
#Module
public EjbJar beans() {
EjbJar ejbJar = new EjbJar();
ejbJar.addEnterpriseBean(new StatelessBean(ProcessorBean.class));
ejbJar.addEnterpriseBean(new StatelessBean(MockDao.class));
return ejbJar;
}
#Test
public void test() throws Exception {
// use your processorBean
}
}
Here we see a testcase run by the ApplicationComposer. It is a simple wrapper for a JUnit test runner that looks for #Module methods which can be used to define your app.
This is actually how OpenEJB has done all its internal testing for years and something we decided to open up in the last few releases (since 3.1.3). It's beyond powerful and extremely fast as it cuts out classpath scanning and some of the heavier parts of deployment.
The maven dependencies might look like so:
<dependencies>
<dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0-3-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<!--
The <scope>test</scope> guarantees that none of your runtime
code is dependent on any OpenEJB classes.
-->
<dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>openejb-core</artifactId>
<version>4.0.0-beta-1</version>
<scope>test</scope>
</dependency>
</dependencies>
If you want to mock any object or create its stub, you can use additional library, e.g. Mockito. It allows you very easily mock any class or even an interface.
Additional reading:
Mocks Aren't Stubs by Martin Fowler
Series of Effective Mockito articles on DZone
How would you go about integration testing a spring application that is annotation-configured and component-scanned and does not have an XML configuration at all? I'm hitting a wall with the need to replace production components with testing components without actually resorting to xml configuration or reflection injections to all the #autowired parts.
Example:
interface A {...}
#Component
class AImpl implements A {
...
}
interface B {...}
#Component
class BImpl implements B {
#Autowired A a;
...
}
interface C {...}
class CImpl implements C {
#Autowired B b;
...
}
then in my test I want to use ATestImpl, but I only have access to C (integration testing C).
How would you go about doing that?
Take advantage of #Primary annotation:
#Service
#Primary
public class TestA implements A {
//...
}
If there is more than one bean implementing A, Spring will prefer the one annotated with #Primary. If you place TestA class in /src/test/java, it will only be picked up during test execution, on normal context startup Spring won't see TestA and use only avaialble AImpl.
Use a dedicated spring context XML file where you override AImpl with an instance of ATestImpl. Of course, it uses XML, but I don't see any other solution (other than repackaging the application with your ATestImpl annotated class instead of the AImpl one)
The new Bean Profile features in Spring 3.1 address the need to swap injected components for testing by defining profiles e.g. test, production etc.
The link to the blog post is here. The Spring team have today released the second milestone release of Spring 3.1.
You can use a special component scan for your test, that exclude the "normal" class and add the test class.
If you have several different test classes, then they should not have a #Component Annotation (or #Service, ...). Instead they should be loaded by an XML Bean declaration. So you can have different XML files for different setups.
<context:component-scan base-package="com.queomedia.sgcrm.base">
<context:exclude-filter expression="com\.example\.AImpl" type="regex"/>
</context:component-scan>
<bean class="com.example.ATestImpl"/>
Using Spring annotation config classes, code the #Bean methods to interfaces. The prod config can perform a componentscan on the high-level package(s) to load the prod objects and the test configs can individually specify beans to return the test versions of your objects. This works very well for component testing where faking service calls and DAO objects is necessary.
I have a routes defined in CamelRoutes.xml and I would like to test them by using the wrapping technique described at the bottom of http://camel.apache.org/mock.html.
My CamelRoutes.xml
<route autoStartup="true" xmlns="http://camel.apache.org/schema/spring">
<from uri="direct:start"/>
<to uri="direct:end"/>
</route>
So I created CamelRoutesTest.xml containing:
<import resource="CamelRoutes.xml"/>
<bean id="mockAllEndpoints" class="org.apache.camel.impl.InterceptSendToMockEndpointStrategy"/>
but I am not sure how to create a test that both loads the spring xml AND provides access to the mock endpoints.
If I use..
#ContextConfiguration( locations=("/CamelRoutesTest"))
public class CamelTest extends AbstractJUnit38SpringContextTests
}
then I have no idea how to get the mock endpoints
If I use..
public class CamelTest extends CamelTestSupport
}
then I dont know how to load my camel context..
I can't seem to find an example test on the website that uses CamelTestSupport AND loads routes from spring xml.
Tom you already posted this on the Camel mailing list. I suggest that you write this when you post a Q here as well.
The answer is already posted here
http://camel.465427.n5.nabble.com/Problems-testing-Camel-with-Spring-config-tp4267754p4267754.html
Solved using:
public class CamelTest extends CamelSpringTestSupport {
#Override
protected AbstractXmlApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext("/CamelRoutesTest.xml");
}
#Test
#DirtiesContext
public void discover() throws Exception {
getMockEndpoint("mock:my.route.out").expectedMessageCount(1);
template.sendBody("direct:my.route.in", FileUtils.slurpClassPathFile("/samples/sample.data.xml"));
assertMockEndpointsSatisfied();
}
}
Thanks for this solution, #Tom !
I also had a hard time getting Camel to work with my Spring-powered JUnit tests, problem is the suggested CamelSpringJUnit4ClassRunner has now moved from camel-spring.jar to a separate module, camel-spring-test.jar, which is not available in the standard camel-distribution as of 2.9.2.
So I cannot use #RunWith but had to resort to the manual method described in the solution...