QAF cucumber testNG with spring boot - spring-boot

I have a cucumber project that uses spring boot and testng.
Here the principal classes
#SpringBootTest
public class CucumberTestDefinitions extends FunctionalTesting {
#Given("Something")
public void smthg(){
}
}
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = FunctionalTestingApp.class, initializers =
ConfigFileApplicationContextInitializer.class)
public class FunctionalTesting {
#Autowired
protected FunctionalTestingConfiguration configuration;
}
#EnableConfigurationProperties(value = {FunctionalTestingConfiguration.class})
public class FunctionalTestingApp {
}
#EnableAutoConfiguration
#ConfigurationProperties(prefix = "testing")
#Data
public class FunctionalTestingConfiguration {
// the config from yml file
}
I have no testng.xml file as tests are launched with spring-boot.
For some reasons, I would like to prioritize tests and I saw I could do with QAF (https://qmetry.github.io/qaf/latest/scenario-meta-data.html#pre-defined-meta-data-for-bdd).
I tried to use it but it didn't work.
Here what I did:
I added the dependency to pom.xml (I use cucumber 5)
I added this annotation #QAFTestStepProvider to CucumberTestDefinitions class
I added this plugin "com.qmetry.qaf.automation.cucumber.QAFCucumberPlugin" in RunnerTest class
Here the error
java.lang.NoSuchMethodError: 'java.lang.reflect.Method com.qmetry.qaf.automation.step.client.TestNGScenario.getMethod()'
I tried adding a testng.xml file in config folder but it didn't help
Is QAF spring-boot compatible?
Thanks a lot for helping
EDIT
pom.xml :
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>5.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.qmetry</groupId>
<artifactId>qaf-cucumber</artifactId>
<version>3.0.0</version>
</dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
The Runner class
features = {"src/test/resources/toto"})
public class RunnerTest extends AbstractTestNGCucumberTests {
#Autowired
private ObjectMapper objectMapper;
#Override
#DataProvider(parallel = true)
public Object[][] scenarios() {
return super.scenarios();
}
#PostConstruct
public void setUp() {
objectMapper.registerModule(new JavaTimeModule());
}
}
error message
java.lang.NoSuchMethodError: 'java.lang.reflect.Method com.qmetry.qaf.automation.step.client.TestNGScenario.getMethod()'
at com.qmetry.qaf.automation.step.client.TestNGScenario.init(TestNGScenario.java:92)
at com.qmetry.qaf.automation.step.client.TestNGScenario.<init>(TestNGScenario.java:70)
at com.qmetry.qaf.automation.step.client.TestNGScenario.<init>(TestNGScenario.java:64)
at com.qmetry.qaf.automation.testng.TestRunnerFactory.convert(TestRunnerFactory.java:76)
at com.qmetry.qaf.automation.testng.TestRunnerFactory.init(TestRunnerFactory.java:67)
at com.qmetry.qaf.automation.testng.TestRunnerFactory.newTestRunner(TestRunnerFactory.java:63)
at org.testng.ITestRunnerFactory.newTestRunner(ITestRunnerFactory.java:55)
at org.testng.SuiteRunner$ProxyTestRunnerFactory.newTestRunner(SuiteRunner.java:676)
at org.testng.SuiteRunner.init(SuiteRunner.java:178)
at org.testng.SuiteRunner.<init>(SuiteRunner.java:112)
at org.testng.TestNG.createSuiteRunner(TestNG.java:1275)
at org.testng.TestNG.createSuiteRunners(TestNG.java:1251)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1100)
at org.testng.TestNG.runSuites(TestNG.java:1039)
at org.testng.TestNG.run(TestNG.java:1007)
at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66)
at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:110)

Unfortunately, i was not able to reproduce the same error and getting other errors regarding dependencies. However to address your original question "QAF cucumber testNG with spring boot" and aspect "like to prioritize tests" short answer is yes. But probably not both TESTNG and Cucumber runner together, especially prioritize tests. What does this mean?
When you are using cucumber suggested way for TestNG, it just creates one dummy test in TestNG and feeds scenarios as test data. Which will not capable to consider each scenario as independent TestNG test! so you won't be able to take all benefits from TestNG (for example, priority).
However, it doesn't mean that you can't can't achieve or can't use QAF+Cucmber+TestNG together. When you use QAF it has pure TestNG implementation for BDD. QAF considers each scenario as TestNG test and Scenario with examples (scenario outline) as data-driven test. qaf-cucuber will enable to use cucumber steps including dependency injection of your choice, Spring in your case. You will get benefit of all TestNG features including parallel execution, listeners and extended features from QAF like meta-data filter, test-data filter,
So when you want to use TestNG it is better to provide TestNG configuration to run your feature files written in BDD2 or Gherkin (subset of BDD2). All you need to do is create following XML file to run feature file written using BDD2 or Gherkin.
<suite name="QAF Demo" verbose="0">
<parameter name="step.provider.pkg" value="pkg.from.where.steps.needs.tobe.loaded" />
<parameter name="scenario.file.loc" value="src/test/resources/toto" />
<test name="BDD Test" enabled="true">
<classes>
<class name="com.qmetry.qaf.automation.step.client.text.BDDTestFactory2"></class>
</classes>
</test>
</suite>
Note:
set step.provider.sharedinstance to true when using cucumber step implementation with class variables used in step.
In above way, as you are not using cucumber runner, so any cucumber hooks will not be executed. When you are using TestNG, it has better listener support that you can utilize and step listener you can use available with QAF. So if you have any hooks implemented you can move that in appropriate before/after listener methods and register listener in configuration file.
EDIT:
I tried the test project which you shared, with it also i run into different issues. Finally i was able to figured it out as below.
POM updates:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
<scope>test</scope>
</dependency>
You have two choices. Using BDD2 Factory which creates TestNGScenario for each scenario or the cucumber runner way. In either case it should work. You can add reporting dashboard to view reports after execution.
Option-1: pure Testng
Create config file to run as pure Testng test using BDDTestFactory2:
<suite name="QAF Demo" verbose="0">
<parameter name="step.provider.pkg" value="my.custom.packagename.testing"/>
<parameter name="scenario.file.loc" value="src/test/resources/my/custom/packagename/testing"/>
<parameter name="step.provider.sharedinstance" value="true" />
<test name="BDD Test" enabled="true">
<classes>
<class name="com.qmetry.qaf.automation.step.client.text.BDDTestFactory2"></class>
</classes>
</test>
</suite>
Use this config file instead of your runner class. In this case you don't required cucumber-testng dependency.
Option-2: cucumber runner for Testng
you will required cucumber-testng dependency
To run using your cucumber runner use same version for cucumber and cucumber testng. In your case cucumber-* version needs to be same either 5.6.0 or 5.4.0
Update runner class as below:
#CucumberOptions(plugin = {"com.qmetry.qaf.automation.cucumber.QAFCucumberPlugin", "pretty", "html:target", "timeline:target"},
/*tags = {"#Ignore"},*/
features = {"src/test/resources/my/custom/packagename/testing"})
public class RunnerTest extends AbstractTestNGCucumberTests {
#Autowired
private ObjectMapper objectMapper;
#Test(groups = "cucumber", description = "Runs Cucumber Scenarios", dataProvider = "scenarios")
public void runScenario(PickleWrapper pickleWrapper, FeatureWrapper featureWrapper) throws Throwable {
super.runScenario(pickleWrapper,featureWrapper);
}
#Override
#DataProvider(parallel = true, name = "scenarios")
public Object[][] scenarios() {
return super.scenarios();
}
#PostConstruct
public void setUp() {
objectMapper.registerModule(new JavaTimeModule());
}
}
Run as TestNG.

Related

Not able to inject #Service and #Contract dependency in my resource class

On base of the guide from this blog, Roll your own Auto Discovery with Jersey and HK2, I have the follow resource POJO:
#Path("Test")
public class TestResource {
#Inject
private TestService service;
#GET
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Set<Test> getTests() {
return service.getAllTests();
}
}
The TestService:
#Contract
public interface TestService {
public Set<Test> getAllTests();
}
The TestServiceImpl
#Service
public class TestServiceImpl implements TestService {
#Override
public Set<Test> getAllTests() {
Set<Test> tests = new HashSet<>();
Test c = new Test();
c.setName("test");
tests.add(c);
return tests;
}
}
The Jersey dependency in pom.xml is of version 2.25.1
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>
<dependency>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2</artifactId>
<version>2.5.0-b36</version>
</dependency>
In order to make Jersey scan the #Service and #Contract classes automatically, I used the inhabitant-generator plugin with version 2.5.0-b36:
<plugin>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-inhabitant-generator</artifactId>
<version>2.5.0-b36</version>
<executions>
<execution>
<goals>
<goal>generate-inhabitants</goal>
</goals>
</execution>
</executions>
</plugin>
There is the corresponding Feature implementation:
public class AutoServiceDiscovery implements Feature {
#Override
public boolean configure(FeatureContext context) {
ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(context);
DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
Populator populator = dcs.getPopulator();
try {
populator.populate(new ClasspathDescriptorFileFinder(this.getClass().getClassLoader()),
new DuplicatePostProcessor());
} catch (IOException | MultiException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
}
return true;
}
}
And it is indeeded registered through my ResourceConfig class:
#ApplicationPath("/*")
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
packages("resources");
register(new AutoServiceDiscovery());
}
}
However, I send request to the /test, got the following error:
MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for
injection at SystemInjecteeImpl(requiredType=TestService,parent=TestResource,qualifiers=
{},position=-1,optional=false,self=false,unqualified=null,1947073589)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of
rx.practice.ee.jaxrs.resources.TestResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on
rx.practice.ee.jaxrs.resources.TestResource
org.jvnet.hk2.internal.Collector.throwIfErrors(Collector.java:89)
org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:250)
org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:358)
org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:487)
org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:162)
...
Question: Anyone knows why the #Service class cannot be injected? I am using Tomcat server
After a couple of days research on the source code of inhabitat-generator, I figured out that in case of web application package,war, the locator file is not generated in META-INF/hk2-locator as demonstracted in the HK2 Inhabitant Generator office site in case of using jar as deployment package. The source code of AbstractInhabitantsGeneratorMojo.java told that in case of war, locator files are generated in hk2-locator, and this is not mentioned in the HK2 Inhabitant Generator office site.
However, when constructing the ClasspathDescriptorFileFinder without the directory names argument in the bootstrap class, AutoServiceDiscovery, it is only compatible with jar as deployment package, meaning it is only finding files in META-INF/hk2-locator.
So the better solution would be not to use inhabitant-generator plugin but the metadata-generator dependency, which is an annotation processor at compile time and, it is proved out-of-the-box.
If someone is persistent to using this plugin, he/she could create his/her own ClasspathDescriptorFileFinder so that it is able to find locator files from hk2-locator
Last but not least, I also tried to use the inhabitants-generator plugin's options to generate the locator files in hk2-locator, but this seems to be next to impossible as well

#Given or #When annotation of cucumber is throwing errors related spring boot configuration

I am writing cucumber BDD test cases .
All the dependencies of cucumber are included in pom.xml
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.trivago.rta</groupId>
<artifactId>cluecumber-report-plugin</artifactId>
<scope>test</scope>
<version>2.3.3</version>
</dependency>
In My step definition file , i have included SprintBootTest annotation
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AccessProfileStepDefinition {
private final Logger log = LoggerFactory.getLogger(AccessProfileStepDefinition.class);
// Location of input payload, which will be used to send request to api server.
private static final String root_folder = "/testdata/bdd/json_for_accessprofile/";
private final static String create_useraccessprofile_payload = root_folder + "create_access_profile_req.json";
#Autowired
private AccessProfileHttpClient httpClient;
#Given("I am cbx system user")
public void i_am_cbx_system_user() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.PendingException();
}
I get error -
when i am run my test
mvn -DAccessProfileFeatureBDDTest clean test
java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test
If i comment #Given clause in my step definition file, then i do not get the error related to #SpringBootConfiguration
Other files . is below
package com.igtb.dcp.cbxaccessprofile.bdd;
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
#RunWith(Cucumber.class)
#CucumberOptions(features = "src/test/resources/features/accessprofile/", plugin = {
"json:target/cucumber-report/cucumber.json", "com.igtb.dcp.cbxaccessprofile.bdd.TestInitialization" })
public class AccessProfileFeatureBDDTest {
}
accessprofile.feature has the feature and is contained in src/test/resources/features/accessprofile/ folder
If i comment #Given clause in my step definition file, then i do not get the error related to #SpringBootConfiguration
If you don't have a step definition in the class annotated with the context configuration Cucumber will not detect any context configuration at all and fall back to a GenericApplicationContext.
java.lang.IllegalStateException: Unable to find a
#SpringBootConfiguration, you need to use #ContextConfiguration or
#SpringBootTest(classes=...) with your test
With this error Spring is telling you that your #SpringBootTest couldn't find any configuration to build the application context from.
You either have to explicitly reference a class annotated with #SpringBootconfiguration, or make sure your #SpringBootApplication annotated class is in the same package, or add a #ContextConfiguration annotation to the AccessProfileStepDefinition.

Cucumber Spring DI two Step classes loading Spring context

I'm using cucumber-spring to create my integration tests and use DI provided by Spring.
The way it's done: there is a separate project that defines all the necessary cucumber dependencies:
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
</dependency>
The project also has a base test class annotated with SpringBootTest (that allows to load application context):
#RunWith(SpringRunner.class)
#SpringBootTest(
classes = {SomeBeans.class}
)
public class BaseTestStateSteps {
I'm adding this project as a dependency in the pom of my project:
<dependency>
<groupId>com.externalproject</groupId>
<artifactId>spring-test-cucumber</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
Then I have my runner class:
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {"pretty", "junit:target/cucumber/cucumber.xml", "json:target/cucumber/cucumber.json",
"html:target/cucumber/html/"},
tags = {"#Smoke"},
features = {"src/test/resources/features"},
glue = {"com.externalproject.steps","com.mycompany.steps"}
)
public class RunTestIT {
}
And I also have my Step class:
public class MyTestSteps {
#Autowired
ClassToAutowire classToAutowire;
#Given("^I can do something$")
public void generateRandomPhoneNumber() {
classToAutowirer.doSomething();
}
So the issue I'm running:
- if I don't have my RunTestIT annotated with SpringBootTest or with ContextConfiguration - ClassToAutowire is null (it's not autowired);
- if I addone of those annotations I'm running into error:
cucumber.runtime.CucumberException: Glue class class com.externalproject.steps.BaseTestStateSteps and class com.mycompany.steps.MyTestSteps both attempt to configure the spring context. Please ensure only one glue class configures the spring context
I need the functionality of Steps from external project (so I don't have to copy/paste from there and get the latest feature updates), but I also need dependencies from my spring context to be autowired.
I read the article https://thepracticaldeveloper.com/2018/03/31/cucumber-tests-spring-boot-dependency-injection/
But it only deals with multiple step definitions inside the same project.
Do you have any ideas how I can solve the issue?

SpringBoot 2 + Junit5: null with #Value

I have an application with SpringBoot2 and Junit5, and now I'm trying to make a test. I have a this class called OrderService that looks like this:
#Component
public class OrderService {
#Value("#{'${food.requires.box}'.split(',')}")
private List<String> foodRequiresBox;
#Value("#{'${properties.prioritization}'.split(',')}")
private List<String> prioritizationProperties;
#Value("${further.distance}")
private Integer slotMeterRange;
#Value("${slot.meters.long}")
private Double slotMetersLong;
As you can see, the class has many #Value annotations that extracts values from application.properties file.
In the POM file I have these dependences:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>2.0.5.RELEASE</version>
</dependency>
Tn the test/resources folder I have the application.properties file with this information:
properties.prioritization:vip,food
food.requires.box:pizza,cake,flamingo
further.distance:2
slot.meters.long:0.5
The test file looks like this:
#ExtendWith(SpringExtension.class)
#TestPropertySource(locations="classpath:application.properties")
public class OrderServiceTest {
OrderService orderService;
#BeforeEach
void before(){
orderService = new OrderService();
}
#Test
void findAll() {
Order order = new Order().withDescription("2x Pizza with Salad\\n2x Kebab with Fries\\n1x Hot dog with Fries\\n2x Pizza with Fries");
assertTrue(orderService.orderHasFood.test(order));
}
}
But the test throws NullPointerException when it tries to use foodRequiresBox, so there is a problem to read the application.properties file.
Could you tell how can I read the application.properties file for the tests?
1st Solution
I would recommend to use Spring's internal annotation called #SpringJUnitConfig
This annotation is actually the same as #ExtendWith(SpringExtension.class) BUT you can configure your spring application contexts for your test in the same way you used to use #ContextConfiguration.
Or if you want a full Spring Boot Test you could just combine:
#SpringJUnitConfig
#SpringBootTest
public class OrderServiceTest {
...
}
2nd Solution
Another way is to not use Spring at all, but mock all the internal stuff with e.g. Mockito and write a plain simple Unit Test.
You could then set your normally via Spring injected annotated #Value fields via org.springframework.test.util.ReflectionTestUtils.
I'd recommend using org.springframework.test.util.ReflectionTestUtils (as indicated in #mrkernelpanic second solution) using the setField() method, in order to avoid initializing the full Spring context.
Here is a snippet:
// ReflexionTestUtils.setField(targetObject, "targetFieldName", valueToInject);
ReflexionTestUtils.setField(orderService, "foodRequiresBox", "pizza,cake,flamingo");

Unable to Inject EntityManager in JPA Integration Testing With Arquillian and WildFly

I'm trying do integration testing with the following stack:
App server: Embedded WildFly
CDI container: Weld
Database: In-memory H2
ORM: Hibernate/JPA
Platform: Java 8
OS: Mac OS X 10.10
I've setup basic integration testing with Arquillian (as done here) and I'm able to inject dependencies but injecting EntityManager proves to be a challenge. Dereferencing the entity manager field always results in a NullPointerException.
I've seen many articles (including this and this) but I'm still not able to get this seemingly simple thing to work.
Please see below my pom.xml
<dependencies>
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-7.0</artifactId>
<version>1.0.0.Final</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<!-- JUnit Container Implementation for the Arquillian Project -->
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.protocol</groupId>
<artifactId>arquillian-protocol-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
<version>1.0.0.CR3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-persistence-dbunit</artifactId>
<version>1.0.0.Alpha7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-core</artifactId>
<version>1.1.5.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-bom</artifactId>
<version>1.1.8.Final</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
test-persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="test" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.xyz.hellomaven.DummyEntity</class>
<jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
<!--<jta-data-source>java:/DefaultDS</jta-data-source>-->
<!--<jta-data-source>jdbc/arquillian</jta-data-source>-->
<properties>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="update"/>
<!--<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />-->
</properties>
</persistence-unit>
</persistence>
Test case
#RunWith(Arquillian.class)
public class GreeterTest {
#Inject
private Greeter instance; // Injection works!
#PersistenceContext
private EntityManager em; // Null pointer.
public GreeterTest() {
}
#Deployment
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class)
.addClasses(Greeter.class, PhraseBuilder.class, DummyInterceptor.class)
.addAsResource("logging.properties", "META-INF/logging.properties")
.addAsResource("test-persistence.xml", "META-INF/persistence.xml")
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
#Test
public void testCreateGreeting() {
System.out.println("createGreeting");
assertEquals("Hello, Steve!", instance.createGreeting("Steve"));
}
#Test
public void testPersistence() {
DummyEntity de = new DummyEntity();
de.setId(1l);
de.setName("Petr Cech");
de.setAge(10);
em.persist(de);
Query q = em.createQuery("SELECT d.age FROM DummyEntity d");
assertEquals(10, q.getResultList().get(0));
}
}
Complete Maven project available on GitHub.
Please what am I doing wrong?
just don't use weld, sins data-sources is out of things that could be covered by CI and DI. probably you may mock it with Mokito and stay with light Weld,
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
<version>1.0.0.CR3</version>
<scope>test</scope>
</dependency>
But if you want to deal with real DB use managed jboss (ExampleDS is a demo jboss h2 datasource) or managed glassfish instead.
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-arquillian-container-managed</artifactId>
<version>7.1.1.Final</version>
<scope>test</scope>
</dependency>
ref. https://github.com/arquillian/arquillian-examples/blob/master/arquillian-persistence-tutorial/pom.xml
As stated by #Soloviev Dmitry, you use a CDI container for your integration test, which only enables CDI.
There are two options I see:
First one is to use a wildfly-embedded container configured in your maven project, so during maven phase running your integration-tests, wildfly will be downloaded and your test package will be deployed to it. So with ExampleDS it would work fine, as it comes with Wildfly out of the box.
See this post for details
Second one would consist in not using Arquillian for your integration test. So if your integration test only covers managed beans, (not session beans, Wildfly specific resources, ...), you could just instantiate a CDI container prior to your test execution (in #Before or #BeforeClass annotated method using Junit for example) and then instantiate your EntityManager by using the EntityManagerFactory class, referencing your persistence unit used for this integration test. With this method, you could also create CDI producers to inject other resources for your integration test, mocks, depending on the scope of your test.
maven dependency
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
<version>2.1.2.Final</version>
<scope>test</scope>
</dependency>
The test class
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
import org.junit.*;
public class ExampleIT {
private EntityManager em;
protected static Weld weld;
protected static WeldContainer container;
#BeforeClass
public static void init() {
weld = new Weld();
container = weld.initialize();
}
#AfterClass
public static void close() {
weld.shutdown();
}
#Before
private void before(){
em = Persistence.createEntityManagerFactory("MyPersistenceUnit").createEntityManager();
}
#Test
public void testToto(){
// Do something with entity manager ...
}
}
I usually opt for second solution for Integration tests, because it's easier to setup than Arquillian tests, and faster to execute.
Use the application managed entitymanager.
#PersistenceUnit
EntityManagerFactory emf;
and create entityManager using
EntityManager em = emf.createEntityManager();
a container managed entitymanager is created and injected by container itself. If you are not under a server environment, then you need to use application managed persistence context.
I guess the transaction manager + Entity Manger Factory are missing in your context file. Configure both in test-persistence.xml, then make the entity manager factory a property of the transaction manager.

Resources