4 Replies Latest reply on Mar 28, 2010 11:25 AM by Stuart Douglas

    Example of using Weld and TestNG?

    Anders Åberg Newbie

      Hi guys
      Does anyone have an example of using Weld together with TestNG? I have found some that use Arquillian, but I would like to do it without it if possible. I assume that Weld must be instantiated programmatically in such a setting, for instance in @BeforeSuite, or am I missing something? I have tried several different approaches, but haven't seen any traces of Weld at all during execution.


      Regards,


      Anders

        • 1. Re: Example of using Weld and TestNG?
          Nicklas Karlsson Master

          Have a look at the core tests (under tests in the distro), they are not Arquillianized yet.

          • 2. Re: Example of using Weld and TestNG?
            Wujek Srujek Newbie
            Hi. What I do is:

            1. bootstrap Weld in @BeforeTest (you can choose @BeforeSuite) - note that TestNG @BeforeTest means all test classes within <test> - and store it in the TestNG injected ITestContext:
            @BeforeTest
            public void beforeTest(ITestContext ctx) {
                WeldContainer wc = Weld.initialize();
                BeanManager bm = wc.getBeanManager();
                ctx.setAttribute("beanManager", bm);
            }

            2. in the test class's @BeforeClass I retrieve the BeanManager and perform injection (you can have it in a common superclass):
            @BeforeClass
            public void beforeClass(ITestContext ctx) {
                BeanManager bm = (BeanManager) ctx.getAttribute("beanManager");
                CDIInjector.inject(bm, this); // this is the test class instance
            }

            where CDIInjector is:

            public class CDIInjector {

                @SuppressWarnings({ "rawtypes", "unchecked" })
                public static void inject(BeanManager beanManager, Object instance) {
                    Class<?> clazz = instance.getClass();
                    checkTestMethods(clazz);
                    Annotation[] qualifiers = getQualifiers(beanManager, clazz.getAnnotations());
                    AnnotatedType<?> annotatedType = beanManager.createAnnotatedType(clazz);
                    InjectionTarget<?> injectionTarget = beanManager.createInjectionTarget(annotatedType);
                    Set<Bean<?>> beans = beanManager.getBeans(clazz, qualifiers);
                    if (beans.size() == 0) {
                        throw new IllegalStateException("class '" + clazz.getName()
                                + "' seems not to be a CDI managed bean; make sure it complies with "
                                + "the CDI specification requirements and the class is in a bean "
                                + "archive - there must be a 'beans.xml' file in appropriate location");
                    }
                    Bean<?> bean = beans.iterator().next();
                    CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean);
                    InjectionTarget rawInjectionTarget = injectionTarget;
                    rawInjectionTarget.inject(instance, creationalContext);
                }

                private static void checkTestMethods(Class<?> clazz) {
                    for (Method m : clazz.getMethods()) {
                        if (m.isAnnotationPresent(Inject.class) && (m.isAnnotationPresent(Test.class) || clazz.isAnnotationPresent(Test.class))) {
                            throw new IllegalTestClassException("test method '" + m
                                            + "' is also annotated @Inject - it doesn't make any sense! "
                                            + "it would be invoked by your CDI provider, it would not be "
                                            + "treated as a test at this time and the environment might "
                                            + "not be fully initialized - consider methods it depends on, "
                                            + "any @BeforeMethod callbacks, etc.; it would be executed again "
                                            + "by TestNG; it is very likely to fail and not hence supported");
                        }
                    }
                }

                private static Annotation[] getQualifiers(BeanManager beanManager, Annotation[] annotations) {
                    List<Annotation> qualifiers = new ArrayList<Annotation>(annotations.length);
                    for (Annotation annotation : annotations) {
                        if (beanManager.isQualifier(annotation.getClass())) {
                            qualifiers.add(annotation);
                        }
                    }
                    return qualifiers.toArray(new Annotation[qualifiers.size()]);
                }
            }

            This way you can have your test classes look like:

            public class SomeTest {

                @Inject
                private SomeInjected si;

                @Test
                public void test() {
                    Assert.assertNotNull(si);
                }
            }

            3. shut down Weld in @AfterTest:
            @AfterTest
            public void afterTest(ITestContext ctx) {
                BeanManager bm = (BeanManager) ctx.getAttribute("beanManager");
                if (bm != null) {
                    Weld.shutdown(bm);
                }
            }

            This is a simplified version of what I use and it might have some errors as I didn't check it in the IDE. It should get you started, though. The downside is that this works easiest when you have a base class for test that performs the injection, and you cannot then extends from something else. Arquillian had (has?) the same limitation last time I checked.
            I am not using Arquillian as what I show here was written before we found out about it, a fairly long time ago.

            Hope you find it helpful.
            • 3. Re: Example of using Weld and TestNG?
              Dan Allen Master

              I beg of you to check out Arquillian. It will simplify your life dramatically. Join us on #jbosstesting in IRC too.

              • 4. Re: Example of using Weld and TestNG?
                Stuart Douglas Master

                If you really can't use Arquillian for whatever reason you could look at seam-xml tests, they currently use weld-se. These will be changed to Arquillian in the near future though.