Arquillian TestNG: #Before Annotations and CDI - java

I am using Arquillian and TestNG with CDI.
Before each test I need access to some members that are CDI beans to do some setup before each test. But i noticed that in every #Before annotation the CDI beans were not injected, but in the #Test annotated method they are.
Can someone explain me why:
1) CDI beans are not yet injected in the #BeforeXXX annotated methods part of the test life cyle?
2) How can I do some setup and access CDI beans before the Tests?
3) Would be correct used the "dependency" attribute in the #Test annotation?
Thank you so much.

I think I already understood the problem.
The tests run in two different places:
- in the client: maven jvm
- in the container: server jvm
In the client side, the CDI beans are not available in the #BeforeMethod, but they will when the test is running in the container. Basically if we need to access CDI beans in the before method we just need to make sure that the test is running in the container. To accomplish this i created a class that extends Arquillian and expose a method that does this.
public abstract class BaseArquillianTest extends Arquillian {
#ArquillianResource
protected InitialContext initialContext;
#Deployment
#OverProtocol("Servlet 3.0")
public static WebArchive createDeployment() {
WebArchive war = PackagingUtil.getWebArchiveForEJB();
return war;
}
protected boolean inContainer() {
// If the injection is done we're running in the container.
return (null != initialContext);
}
}
We just have to do this check in #BeforeMethod method
#BeforeMethod(alwaysRun = true)
public void beforeMethod() throws Exception {
System.out.println("********* Initing beforeMethod");
if(inContainer()) {
System.out.println("$$$$$$ I am in a container");
Assert.assertNotNull(allRiskConfigurations);
} else {
System.out.println("$$$$$$ I am NOT in a container");
}
}
In the end, the tests in the client looks like they are ignored to reflect the results of the tests that were executed in the container.
If this is wrong, can someone please correct?
Thank you all anyway. I Hope this help

Related

Spring Boot - how to initialize class from a dependent module with injected dependencies

I have two Maven projects A and B, where project B is nested in project A. The structure looks like the following:
Project A:
src/test/java:
MyTest.java
Project B:
src/test/java:
MyNewTest.java
pom.xml
pom.xml
My goal is to let MyNewTest.java act as a wrapper of MyTest.java, and be able to invoke the test methods declared in MyTest.java from MyNewTest.java. MyTest has some injected dependencies.
My question is: how to initialize MyTest in MyNewTest to make sure that all the dependencies of MyTest are injected properly?
MyTest looks like the following:
public class MyTest {
#Autowired
Service service;
#Autowired
TestUtil util;
Info info;
#PostConstruct
void init() {
info = service.getStuff();
}
#Test
public test1() {
service.getMoreStuff();
// more code omitted
}
}
I have tried adding #Component to MyTest, and then in MyNewTest.java, use #Autowired like the following:
public class MyNewTest {
#Autowired
private MyTest baseTest;
#Test
public void runTest() {
// run the test in MyTest.java
baseTest.test1();
}
}
But this doesn't seem to work - baseTest is null. I also tried initializing MyTest by calling its default constructor, but the dependencies failed to be injected as expected. Can anyone suggest a proper way to initialize MyTest.java so that all its dependencies are injected as well? Thanks
The problem with your test is the #Autowired annotations as the Spring wiring isn't being triggered. There are two different paths you can take to fix this.
The first option is to manually instantiate baseTest in MyNewTest at which point it will no longer be null. However, tests will still fail because your two #Autowired dependencies will be null. You can either add setters or inject them via your constructor. Note- these classes should be mocked if you are performing Unit Tests. Here's how it would look if you chose to add these classes via the constructor -
private Service service;
private TestUtil util;
private MyTest baseTest;
#BeforeEach
void setUp() {
service = mock(Service.class);
util = mock(TestUtil.class);
baseTest = new MyTest(service, util);
}
The second option is to add configuration to your Test class to support the Spring wiring. I am not familiar with taking this route as I always choose the first option when possible. There are multiple ways to add the Spring wiring but the easiest is-
#SpringBootTest
#RunWith(SpringRunner.class)
public class MyNewTest {
However, this does not cover all use cases so you may need more specific configurations. You can find some of the possible options here - How to write JUnit test with Spring Autowire?
Edit- As I immediately recognized a problem, I didn't read the rest very carefully and I missed that these were Test classes you were trying to wire together. I am not sure if this is possible.
Only Spring beans can be #Autowired so the first step would be to attempt to add configuration to make your Test class into a Spring bean. I've never heard of this being done before but it would be easy to try. If not, you can get around this problem by using the first option.
The second problem is that tests are not included in the artifact. I'd imagine you could circumvent this issue by mixing your Test classes in with your regular classes but this is considered a bad practice. I've never heard of tests being dependent on other tests but I'd guess this is also a bad practice. What's the reason for wanting to create your Tests this way?

Unit testing JAX-RS/Jersey servlet with Guice Injections

I have an application that uses Jersey/JAX-RS for web services (annotations, etc) and Guice to inject service implementations. I don't really like the way Guice works with servlets directly, I prefer the Jersey way, so I had to do a bit of fussing to get the service injections to work since Guice wouldn't be creating my servlet classes, and I didn't want to deal with the HK2-Guice bridge. I did this by creating a listener class (called Configuration) that sets up the injectors in static fields upon application startup and then manually effecting the injections in each servlet class by creating a parent class that all my servlets extend with a constructor that contains the following:
public MasterServlet() {
// in order for the Guice #Inject annotation to work, we have to create a constructor
// like this and call injectMembers(this) on all our injectors in it
Configuration.getMyServiceInjector().injectMembers(this);
Configuration.getDriverInjector().injectMembers(this);
}
I know it's kind of hacky, but this works just fine in my servlets. I can use the Guice #Inject annotations on my services and switch between named implementations and so on. The problem comes when I go to set up my unit tests. I'm using JerseyTest to do my tests, but running a test against my servlets results in a 500 error with Guice saying the following:
com.google.inject.ConfigurationException: Guice configuration errors:
1) No implementation for com.mycompany.MyService was bound.
while locating com.mycompany.MyService
for field at com.mycompany.servlet.TestGetServlet.service(TestGetServlet.java:21)
while locating com.mycompany.servlet.TestGetServlet
The test looks like this:
public class TestServletTest extends JerseyTest {
#Test
public void testServletFunctional() {
final String response = target("/testget").request().get(String.class);
assertEquals("get servlet functional", response);
}
#Before
public void setup() {
Configuration configuration = new Configuration();
configuration.contextInitialized(null);
}
#Override
protected Application configure() {
return new ResourceConfig(TestGetServlet.class);
}
}
You'll notice in the setup method I am manually creating my Configuration class since I can't rely on the test container (Grizzly) to create it (I get NullPointerExceptions without those two lines). More about this below.
And here's the servlet being tested:
#Path("/testget")
public class TestGetServlet extends MasterServlet {
#Inject
MyService service;
#GET
#Produces({"text/plain", MediaType.TEXT_PLAIN})
public String testGet() {
//service = Configuration.getServiceInjector().getInstance(MyService.class);
return "get servlet functional";
}
}
Notice the commented line in the testGet() method? If I do that instead and remove the #Inject annotation above, everything works fine, which indicates that Grizzly is not creating my servlets the way I expect.
I think what's happening is that Grizzly doesn't know about Guice. Everything seems to suggest that Grizzly isn't seeing the Configuration class, despite the fact that by putting it in my test's #Before method it seems to be at least available to the classes that use it (see: the commented line in the TestGetServlet class). I just don't know how to fix it.
I'm still trying to figure this out but in the meantime I switched from Guice to HK2, which took a bit of doing but I figured this might be helpful for anyone who runs into this problem in the future.
I consider this an answer because truthfully my attempt to bypass the Guice-HK2 bridge but still use Guice with Jersey might not have been the best idea.
Switching from Guice to HK2 takes a bit of doing and there's no comprehensive guide out there with all the answers. The dependencies are really fussy, for example. If you try to use Jersey 2.27 you may run into the famous
java.lang.IllegalStateException: InjectionManagerFactory not found
error. Jersey 2.27 is not backwards compatible with previous versions due to HK2 itself. I am still working on getting that all to work, but in the meantime I had to downgrade all my Jersey dependencies to 2.26-b06 to get HK2 working properly.
Jersey thankfully already implements a bunch of HK2 boilerplate, so all you need to get injection working is proper use of #Contract, #Service (see HK2 docs for those), and then two new classes that look like this:
public class MyHK2Binder extends AbstractBinder {
#Override
protected void configure() {
// my service here is a singleton, yours might not be, so just omit the call to in()
// also, the order here is switched from Guice! very subtle!
bind(MyServiceImpl.class).to(MyService.class).in(Singleton.class);
}
}
And this:
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(new MyHK2Binder());
packages(true, "com.mycompany");
}
}
Simple enough, but this only works for the application itself. The test container knows nothing about it, so you have to redo the Binder and ResourceConfig yourself in your test class, like this:
public class TestServletTest extends JerseyTest {
#Test
public void testServletFunctional() {
final String response = target("/testget").request().get(String.class);
assertEquals("get servlet functional", response);
}
#Before
public void setup() {
}
#Override
protected Application configure() {
return new TestServletBinder(TestGetServlet.class);
}
public class TestServletBinder extends ResourceConfig {
public TestServletBinder(Class registeree) {
super(registeree);
register(new MyHK2Binder());
packages(true, "com.mycompany");
}
}
}
Having to do this is actually fine because you can switch out the Binder for a test binder instead, in which you've bound your service to a mocked service instead or something. I haven't done that here but that's easy enough to do: replace new MyHK2Binder() in the call to register() with one that does a binding like this instead:
bind(MyTestServiceImpl.class).to(MyService.class).in(Singleton.class);
And voila. Very nice. Obviously you could achieve a similar result with Named bindings, but this works great and might even be simpler and more clear.
Hope this helps someone save the hours I spent screwing around to get this working.

How can I make a unit test that tests my Spring/OSGi configuration?

I have a bundle-context-osgi.xml file that lists services my project takes and services it publishes. I also have a bundle-context.xml that defines the beans defined in my application. How can I write a unit test that ensures that everything is wired correctly and I can product the services that my application is supposed to provide when it is on the server?
Note: it might be wrong to call this a "unit test" but I think the idea is clear.
For OSGi Integration Tests I usually use Pax Exam. It will start a osgi container publish all configured bundles and will create a tiny-bundle from the testsources to be deployed as a OSGi bundle.
With it you are able to access all registered services even by #Inject means.
Best to take a look at the Pax Exam documentation.
In short you create a new integration test module, where you configure your dependencies in the Test case:
#RunWith(PaxExam.class)
#ExamReactorStrategy(PerMethod.class)
public class MyTest {
#Inject
protected BundleContext bundleContext;
#Inject
MyService service;
...
#Configuration
public Option[] configure() {
return options(
workingDirectory("target/paxexam/"),
cleanCaches(true),
junitBundles(),
mavenBundle().groupId("my.group.id")
.artifactId("my-artifact")
.version("1.0.0")
...
);
}
...
#Test
public void test() throws Exception {
assertNotNull(service);
}
}

Arquillian test failed when bean in ViewScoped

I am writing tests with Arquillian embedded. But i am facing issue when my bean is in View Scope. I just posted my sample code. When my DataBean is in ViewScope it doesn't run and throws some exception. But when i changed it to RequestScope it worked fine.
#RunWith(Arquillian.class)
public class MockTest {
#Deployment
public static Archive<?> createDeployment() {
JavaArchive jar = ShrinkWrap.create(JavaArchive.class)
.addClass("pack.ui.DataBean")
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
return jar;
}
#Inject
private DataBean dataBean;
#Test
public void testDataBean() throws Exception {
dataBean.checkSystemStatus();
Assert.assertEquals(status, true);
}
#ViewScoped
#Named("dataBean")
public class DataBean {
public boolean checkSystemStatus() {
return true;
}
}
Can someone please tell, Can we use ViewScope with Arquillian or anything else i have to do.
It's because the view scope is not active during the invocation of your test. To run it this way, you'll need to use something like drone/graphene. It's not active because the HTTP request that runs is against the arquillian test runner servlet, not the webpage of your application. ViewScope is specific to a page in your application.
You can mock JSF context of controllers and get rid of annoying exception "No active contexts for scope type ViewScoped" during Arquillian test execution.
Check the original project for JSF 2.0: https://github.com/it-crowd/mock-contexts-extension
or my upgrade for JSF 2.2: https://github.com/kesha/mock-contexts-extension
All you need is the additional annotation #ViewScopeRequired before the test method.

integration testing spring service layer based on migrated data

#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"/applicationContext-test.xml"})
#Transactional
public class MyServiceTest {
#Resource(name="myService")
public MyService myService;
#Test
public void testSeomthing() {
//do some asserts using myService.whatever()
}
}
However the tests are based on data I migrate in, so every time I run my suite of tests I want to execute my unrelated migration code. I don't want to run a #Before in each test class. I want to run it once at beginning of complete test process, where can I put this ?
I would advice you to create a test bean somewhere with startup logic invoked in #PostConstruct:
#Service
public class TestBean {
#PostConstruct
public void init() {
//startup logic here
}
}
Obviously this bean should only be created for tests, the easiest way to achieve this is to place it in src/test/java in a package that is component-scanned by Spring for #Service-annotated classes.
Note: you must remember that #PostConstruct is not running in a transaction! See How to call method on spring proxy once initialised.
JUnit also offers a #BeforeClass annotation which you can place on a static method to initialize resources just once.

Categories