Make it test-driven with CDI!




Rafael Liu
the red




          2
Runtime environment




                      3
Test environment




                   4
Unit test




            5
What about...
●
    Access level modifiers limitations?
    ●
        Injection uses reflection
●
    “Unit” related stuff?
    ●
        Bean lifecycle (@PostConstruct, @PreDestroy)
    ●
        Interceptors / Decorators
    ●
        Events



                                                       6
Integration test




                   7
the green(s)




               8
1. CDI @Alternatives
●
    Typesafe bean resolution
●
    Abstraction + implementation
    ●
        “Real” implementation
    ●
        Mock implementation
●
    Runtime vs. test classpath
    ●
        beans.xml



                                      9
Extracting an interface




                          10
Creating a mock @Alternative




                               11
The classpath magic




                      12
2. Arquillian
●
    JBoss Testing initiative
●
    Test enrichment
●
    Inside-container testing
    ●
        JBoss AS 5 and 6
    ●
        GlassFish 3
    ●
        Tomcat 6
    ●
        Jetty 6 and 7

                                        13
A code is worth a thousand words
@RunWith(Arquillian.class)
public class TemperatureConverterTest {

      @Inject
      private TemperatureConverter converter;

      @Deployment
      public static JavaArchive createTestArchive() {
            return ShrinkWrap.create(JavaArchive.class, "test.jar")
                  .addClasses(TemperatureConverter.class)
                  .addAsManifestResource(
                        EmptyAsset.INSTANCE,  
                        ArchivePaths.create("beans.xml"));  
      }

      @Test
      public void testConvertToCelsius() {
            Assert.assertEquals(converter.convertToCelsius(32d), 0d);
            Assert.assertEquals(converter.convertToCelsius(212d), 100d);
      }
}

                                                                           14
The Arquillian way




                     15
Nice!
●
    We can check state
●
    More meaningful units, the CDI beans!
    ●
        A one unit integration test
●
    Mocks can replace beans easily
●
    Custom builds
    ●
        Descriptors and classes



                                            16
But...
●
    Still a class per mock
●
    Various @Deployments
●
    The single implementation dilema
●
    We can't use mock frameworks anymore!




                                            17
refactoring




              18
What we want?




                19
Write a portable extension!
●
    Choose certain injection points
●
    Resolve beans to custom mocks
●
    Define mocks at runtime
●
    Power of mock frameworks


●
    Thanks to our clever Expert Group!


                                         20
A “real” case
@Named
public class MyBean {

   @Inject
   private MyDependency myDependency;

   public String calculate(int a, int b) {
      return "multiplication is " + myDependency.multiply(a, b);
   }

}

@Named
public class MyDependency {

   public int multiply(int a, int b) {
      return a*b;
   }

}


                                                                   21
A code is worth.. you know
public class MyTest extends WeldMockTest {
   
    @Test
    public void testMock() {
       mockContext.addExpectations(new Expectations<MyDependency>() {
          @Override
          public void defineExpectations(MyDependency mock) {
            when(mock.multiply(2, 3)).thenReturn(5);
         }
      });
      
       MyBean bean = getBean(MyBean.class);

      String calculate = bean.calculate(2, 3);
      assertThat(calculate, is("multiplication is 5"));

      calculate = bean.calculate(2, 4);
      assertThat(calculate, is(not("multiplication is 8")));
   }

}


                                                                        22
And a spy
public class MyTest extends WeldMockTest {
      
   @Test
   public void testSpy() {
       mockContext.addExpectations(DoubleType.SPY,
             new Expectations<MyDependency>() {

          @Override
          public void defineExpectations(MyDependency mock) {
            when(mock.multiply(2, 3)).thenReturn(5);
         }
      });
      
       MyBean bean = getBean(MyBean.class);

      String calculate = bean.calculate(2, 3);
      assertThat(calculate, is("multiplication is 5"));

      calculate = bean.calculate(2, 4);
      assertThat(calculate, is("multiplication is 8"));
   }

}
                                                                23
What we get
●
    It's an extension
    ●
        Arquillian friendly
    ●
        Can easy the pain of @Deployments
●
    Mock frameworks and all their greatness!
●
    Choose precisely where to meddle
    ●
        Fine grained integration test
●
    Get a hold of your test code base!

                                               24
Fork me!




http://github.com/rafaelliu
                              25
Questions?

     @rafaelliu



     http://rafaelliu.net



                            26
References
 ●
     http://tinyurl.com/5mjgc8
 (http://code.google.com/p/mockito)

 ●
     http://tinyurl.com/cxshm2f
 (http://seamframework.org/Weld)

 ●
     http://tinyurl.com/c8qdtx8
 (http://monografias.cic.unb.br/dspace/bitstream/123456789/258/1/monografia.pdf)




                                                                                   27

Make it test-driven with CDI!

  • 1.
    Make it test-drivenwith CDI! Rafael Liu
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
    What about... ● Access level modifiers limitations? ● Injection uses reflection ● “Unit” related stuff? ● Bean lifecycle (@PostConstruct, @PreDestroy) ● Interceptors / Decorators ● Events 6
  • 7.
  • 8.
  • 9.
    1. CDI @Alternatives ● Typesafe bean resolution ● Abstraction + implementation ● “Real” implementation ● Mock implementation ● Runtime vs. test classpath ● beans.xml 9
  • 10.
  • 11.
    Creating a mock@Alternative 11
  • 12.
  • 13.
    2. Arquillian ● JBoss Testing initiative ● Test enrichment ● Inside-container testing ● JBoss AS 5 and 6 ● GlassFish 3 ● Tomcat 6 ● Jetty 6 and 7 13
  • 14.
    A code isworth a thousand words @RunWith(Arquillian.class) public class TemperatureConverterTest {       @Inject       private TemperatureConverter converter;       @Deployment       public static JavaArchive createTestArchive() {             return ShrinkWrap.create(JavaArchive.class, "test.jar")                   .addClasses(TemperatureConverter.class)                   .addAsManifestResource(                         EmptyAsset.INSTANCE,                           ArchivePaths.create("beans.xml"));         }       @Test       public void testConvertToCelsius() {             Assert.assertEquals(converter.convertToCelsius(32d), 0d);             Assert.assertEquals(converter.convertToCelsius(212d), 100d);       } } 14
  • 15.
  • 16.
    Nice! ● We can check state ● More meaningful units, the CDI beans! ● A one unit integration test ● Mocks can replace beans easily ● Custom builds ● Descriptors and classes 16
  • 17.
    But... ● Still a class per mock ● Various @Deployments ● The single implementation dilema ● We can't use mock frameworks anymore! 17
  • 18.
  • 19.
  • 20.
    Write a portableextension! ● Choose certain injection points ● Resolve beans to custom mocks ● Define mocks at runtime ● Power of mock frameworks ● Thanks to our clever Expert Group! 20
  • 21.
    A “real” case @Named publicclass MyBean {    @Inject private MyDependency myDependency; public String calculate(int a, int b) { return "multiplication is " + myDependency.multiply(a, b);    } } @Named public class MyDependency { public int multiply(int a, int b) { return a*b;    } } 21
  • 22.
    A code isworth.. you know public class MyTest extends WeldMockTest {     @Test public void testMock() { mockContext.addExpectations(new Expectations<MyDependency>() { @Override public void defineExpectations(MyDependency mock) {             when(mock.multiply(2, 3)).thenReturn(5);          }       });        MyBean bean = getBean(MyBean.class);       String calculate = bean.calculate(2, 3); assertThat(calculate, is("multiplication is 5"));       calculate = bean.calculate(2, 4); assertThat(calculate, is(not("multiplication is 8")));    } } 22
  • 23.
    And a spy publicclass MyTest extends WeldMockTest {        @Test public void testSpy() { mockContext.addExpectations(DoubleType.SPY, new Expectations<MyDependency>() { @Override public void defineExpectations(MyDependency mock) {             when(mock.multiply(2, 3)).thenReturn(5);          }       });        MyBean bean = getBean(MyBean.class);       String calculate = bean.calculate(2, 3); assertThat(calculate, is("multiplication is 5"));       calculate = bean.calculate(2, 4); assertThat(calculate, is("multiplication is 8"));    } } 23
  • 24.
    What we get ● It's an extension ● Arquillian friendly ● Can easy the pain of @Deployments ● Mock frameworks and all their greatness! ● Choose precisely where to meddle ● Fine grained integration test ● Get a hold of your test code base! 24
  • 25.
  • 26.
    Questions? @rafaelliu http://rafaelliu.net 26
  • 27.
    References ● http://tinyurl.com/5mjgc8 (http://code.google.com/p/mockito) ● http://tinyurl.com/cxshm2f (http://seamframework.org/Weld) ● http://tinyurl.com/c8qdtx8 (http://monografias.cic.unb.br/dspace/bitstream/123456789/258/1/monografia.pdf) 27