Unit Test Candidate Solutions

       Xuefeng.Wu 2012.05
Types of Tests
Types of Tests

        use mock environment : isolation
        single responsibility

        use simulation 3rd applications,
        system ,drivers


        use real 3rd applications, system ,
        drivers
Test context

CSDM

CSDM Demo,
   CSDM
                CSDM Service
 Controller

                Soap services
                                Domain Manager
Applications-
                                Business logic
  2D etc,                                        Model DAO   Files
                    Jetty         managers
  Drivers
Test Targets
Technology Problems
•   Environment and Context for developer
•   Test database prepare for developer
•   Test sample files prepare for developer
•   XML String parameter in service for soap services test
•   XML verify for soap services test
•   Mock Object for domain logic test
•   Model Date verify for domain logic test
•   Files verify for domain logic test
•   Notification verify for domain logic test
•   Unit testing styles for better test code
Test database prepare
• DB Unit/ unitils
• Derby backup, restore on line
• Derby date file recovery with RAM Disk
Test database prepare
• Baseline data
• Each Test data is individual and isolation
DB Unit
    • DbUnit has the ability to export and import
      your database data to and from XML datasets.
public DBUnitSampleTest(String name) { super( name );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, "org.apache.derby.jdbc.ClientDriver" );
System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, "jdbc:derby://localhost:1527/pas;create=true" );
}

protected IDataSet getDataSet() throws Exception {

    return new FlatXmlDataSetBuilder().build(new FileInputStream("D:/Test/pas.xml"));
}

protected DatabaseOperation getSetUpOperation() throws Exception {
    return DatabaseOperation.REFRESH;
}

protected DatabaseOperation getTearDownOperation() throws Exception {
    return DatabaseOperation.NONE;
}




       Perform setup of stale data once for entire test class or test suite
Derby backup, restore on line


String dbURL = "jdbc:derby:salesdb;restoreFrom=D:/dbbackups/salesdb";
Connection conn = DriverManager.getConnection(dbURL);
Derby date file recovery
 • Hey! We use derby!
 • Use Embedded Derbey
 • Restore data files which in RAM Disk

<property name="hibernate.connection.url">
jdbc:derby:database/pas;create=true
</property>

<property name="hibernate.connection.driver_class">
org.apache.derby.jdbc.EmbeddedDriver
</property>
Test sample files prepare
• Dicom files,images,3D files
• Custom file providers
XML String parameter in service
• Soap service is all about xml string in and out
• But it's not easy to provide XML format
  string in Java.
Java StringBuffer

String buildXML() {
StringBuffer sb = new StringBuffer();
 sb.append("<EXPRESSION>");
 sb.append(" <EQUAL>");
 sb.append(" <IDENT>x</IDENT>");
 sb.append(" <PLUS>");
 sb.append(" <INT>3</INT>");
 sb.append(" <TIMES>");
 sb.append(" <INT>4</INT>");
 sb.append(" <INT>5</INT>");
 sb.append(" </TIMES>");
 sb.append(" </PLUS>");
 sb.append(" </EQUAL>");
 sb.append("</EXPRESSION>");
 return sb.toString();
} // buildXML
Read xml file as input



      readFileToString.java
Use Other Language raw string

val input = """
<trophy type="request" version="1.0">
 <patient>
  <parameter key="patient_id" value="" /> C (If patient_id and DPMS_id are both null, PAS shall set Patient=patient_internal_id and
  <parameter key="dpms_id" value=""/> C (If both parameter are not null, use input value. Only above two conditions, others will be
  <parameter key="first_name" value=""/> O
  <parameter key="last_name" value=""/> O
  <parameter key="middle_name" value=""/> O
  <parameter key="prefix" value=""/> O
  <parameter key="suffix" value=""/> O
  <parameter key="birth_date" value=""/> O ("yyyy-MM-dd")
  <parameter key="sex" value=""/> O (male,female,other)
  <parameter key="pregnancy" value=""/> O (not pregnant,possibly pregnant,definitively pregnant,unknown) empty string means not app
  <parameter key="insurance_number" value=""/> O <parameter key="address" value=""/> O
  <parameter key="town" value=""/> O
  <parameter key="postal_code" value=""/> O
  <parameter key="cellular_phone" value=""/> O
  <parameter key="home_phone" value=""/> O
  <parameter key="work_phone" value=""/> O
  <parameter key="comments" value=""/> O
  <parameter key="email" value=""/> O
  <parameter key="photo" value=""/> O
  <parameter key="kdis6_patient_directory" value=""/> O (used for import kdis6 images)
  <parameter key="images_imported" value=""/> C ("true/false", must be pair with kdis6_patient_directory)
  </patient>
</trophy>
"""
XML verify
• The soap service output is xml string
• You can use contains to verify simple value
• But not easy to verify specific value
XmlUnit
• XML can be used for just about anything so
  deciding if two documents are equal to each
  other isn't as easy as a character for character
  match
public void testXPathValues() throws Exception {
 String myJavaFlavours = "<java-flavours><jvm current='some platforms'>1.1.x</jvm>" +
 "<jvm current='no'>1.2.x</jvm><jvm current='yes'>1.3.x</jvm>" +
 "<jvm current='yes' latest='yes'>1.4.x</jvm></java-flavours>";

 assertXpathEvaluatesTo("1.4.x", "//jvm[@latest='yes']", myJavaFlavours);
 assertXpathEvaluatesTo("2", "count(//jvm[@current='yes'])", myJavaFlavours);
 assertXpathValuesEqual("//jvm[4]/@latest", "//jvm[4]/@current", myJavaFlavours);
 assertXpathValuesNotEqual("//jvm[2]/@current", "//jvm[3]/@current", myJavaFlavours);
}
Scala XML

val ns = <foo><bar><baz/>Text</bar><bin/></foo>

ns  "foo" // => <foo><bar>...</bar><bin/></foo>

ns  "foo"  "bar" // => <bar><baz/>Text</bar>


val ns = <foo id="bar"/>

ns  "@id" // => Text(bar)
JRuby REXML


xml = File.read('posts.xml')
puts Benchmark.measure {
   doc, posts = REXML::Document.new(xml), []
   doc.elements.each('posts/post') do |p|
   posts << p.attributes
End
}
Model Date verify
• After execute the method you want to know
  every thing is correct.
Solutions
• DbUnit can also help you to verify that your
  database data match an expected set of
  values.
• Call hibernate Dao Directly
• Verify by other business method
Files verify
• Custom utile

• public static void checkDuplicateFiles(File dir)
Notification verify
• An ActiveMQ client utile
• It should run in other thread and subscript
  before call method
• It should time out if no message received after
  long time
Wait future notification

"There should have imageCreated notification after image is created " should {

    " ok " in {

       val srcPid = DataPrepare.createPatient
       val msg = future(ActiveMQ.receive("topic.imageCreated"))
       val imgId = DataPrepare.prepareImage(srcPid)._1 //wait a 3 second
       awaitAll(3000,msg) foreach{ v => v match {
         case Some(m) => { m.toString must contain (srcPid)
                          m.toString must contain (imgId) }
         case None => 1 must_== 2 }
       }
      }
}
Mock Object
EasyMock
public void testTransferShouldDebitSourceAccount(){

    AccountController controller = new AccountController();

    Account from = createMock(Account.class)

    Account to = createMock(Account.class)

    from.debit(42);

    replay(from);

    replay(to);

    controller.transfer(from,to,42);

    verify(from);

}
jMock
Mockery context = new Mockery();
public void testTransferShouldDebitSourceAccount(){

    AccountController controller = new AccountController();

    Account from = context.mock(Account.class)

    Account to = context.mock(Account.class)

    context.checking(new Expectations() {{

         oneOf(from).debit(42);

    }}

    controller.transfer(from,to,42);

    context.assertIsSatisfied();

}
mockito


public void testTransferShouldDebitSourceAccount(){

    AccountController controller = new AccountController();

    Account from = mock(Account.class)

    Account to = mock(Account.class)

    controller.transfer(from,to,42);

    verify(from).debit(42);

}
public void testTransferShouldDebitSourceAccount(){

                                     AccountController controller = new AccountController();

                                     Account from = createMock(Account.class)

                                     Account to = createMock(Account.class)

                                     from.debit(42);

                                     replay(from);

                                     replay(to);

                                     controller.transfer(from,to,42);

                                     verify(from);
                            }


Mockery context = new Mockery();
public void testTransferShouldDebitSourceAccount(){

      AccountController controller = new AccountController();

      Account from = context.mock(Account.class)

      Account to = context.mock(Account.class)

      context.checking(new Expectations() {{
              oneOf(from).debit(42);
      }}

      controller.transfer(from,to,42);

      context.assertIsSatisfied();
}


          public void testTransferShouldDebitSourceAccount(){

                 AccountController controller = new AccountController();

                 Account from = mock(Account.class)

                 Account to = mock(Account.class)

                 controller.transfer(from,to,42);

                 verify(from).debit(42);

          }
Mock what?
Environment and Context
Name                  Location   Interaction

DB                    Internal   JDBC connect with hibernate

ActiveMQ              Internal   socket,ActiveMQ library

Demo                  External   cmd,socket

Config file           External   read/write file

Registration table    External   system tool,reg

Schedule              External   trigger

2D                    External   cmd,socket

Object Applications   External   cmd
Unit testing styles
• BDD
• Better test code
• It’s better not only for developer. If P.O. can
  read our test code is better
• The test code should like specifics
Traditional Status assert test

 public void testAdd() {

     int num1 = 3;

     int num2 = 2;

     int total = 5;

     int sum = 0;

     sum = Math.add(num1, num2);

     assertEquals(sum, total);
 }
BDD specifications style
class HelloWorldSpec extends Specification {

    "The 'Hello world' string" should {

        "contain 11 characters" in {
            "Hello world" must have size(11)
        }

        "start with 'Hello'" in {
            "Hello world" must startWith("Hello")
        }

        "end with 'world'" in {
            "Hello world" must endWith("world")
        }
    }

    "The sum" should {
         “ equals total " in {
             val num1 = 2,num2 = 3, total = 5
            Math.add(num1, num2) must equalsTo(total)
        }
    }

}
Unit test candidate solutions
Unit test candidate solutions

Unit test candidate solutions

  • 1.
    Unit Test CandidateSolutions Xuefeng.Wu 2012.05
  • 2.
  • 3.
    Types of Tests use mock environment : isolation single responsibility use simulation 3rd applications, system ,drivers use real 3rd applications, system , drivers
  • 4.
    Test context CSDM CSDM Demo, CSDM CSDM Service Controller Soap services Domain Manager Applications- Business logic 2D etc, Model DAO Files Jetty managers Drivers
  • 5.
  • 6.
    Technology Problems • Environment and Context for developer • Test database prepare for developer • Test sample files prepare for developer • XML String parameter in service for soap services test • XML verify for soap services test • Mock Object for domain logic test • Model Date verify for domain logic test • Files verify for domain logic test • Notification verify for domain logic test • Unit testing styles for better test code
  • 7.
    Test database prepare •DB Unit/ unitils • Derby backup, restore on line • Derby date file recovery with RAM Disk
  • 8.
    Test database prepare •Baseline data • Each Test data is individual and isolation
  • 9.
    DB Unit • DbUnit has the ability to export and import your database data to and from XML datasets. public DBUnitSampleTest(String name) { super( name ); System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, "org.apache.derby.jdbc.ClientDriver" ); System.setProperty( PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, "jdbc:derby://localhost:1527/pas;create=true" ); } protected IDataSet getDataSet() throws Exception { return new FlatXmlDataSetBuilder().build(new FileInputStream("D:/Test/pas.xml")); } protected DatabaseOperation getSetUpOperation() throws Exception { return DatabaseOperation.REFRESH; } protected DatabaseOperation getTearDownOperation() throws Exception { return DatabaseOperation.NONE; } Perform setup of stale data once for entire test class or test suite
  • 10.
    Derby backup, restoreon line String dbURL = "jdbc:derby:salesdb;restoreFrom=D:/dbbackups/salesdb"; Connection conn = DriverManager.getConnection(dbURL);
  • 11.
    Derby date filerecovery • Hey! We use derby! • Use Embedded Derbey • Restore data files which in RAM Disk <property name="hibernate.connection.url"> jdbc:derby:database/pas;create=true </property> <property name="hibernate.connection.driver_class"> org.apache.derby.jdbc.EmbeddedDriver </property>
  • 12.
    Test sample filesprepare • Dicom files,images,3D files • Custom file providers
  • 13.
    XML String parameterin service • Soap service is all about xml string in and out • But it's not easy to provide XML format string in Java.
  • 14.
    Java StringBuffer String buildXML(){ StringBuffer sb = new StringBuffer(); sb.append("<EXPRESSION>"); sb.append(" <EQUAL>"); sb.append(" <IDENT>x</IDENT>"); sb.append(" <PLUS>"); sb.append(" <INT>3</INT>"); sb.append(" <TIMES>"); sb.append(" <INT>4</INT>"); sb.append(" <INT>5</INT>"); sb.append(" </TIMES>"); sb.append(" </PLUS>"); sb.append(" </EQUAL>"); sb.append("</EXPRESSION>"); return sb.toString(); } // buildXML
  • 15.
    Read xml fileas input readFileToString.java
  • 16.
    Use Other Languageraw string val input = """ <trophy type="request" version="1.0"> <patient> <parameter key="patient_id" value="" /> C (If patient_id and DPMS_id are both null, PAS shall set Patient=patient_internal_id and <parameter key="dpms_id" value=""/> C (If both parameter are not null, use input value. Only above two conditions, others will be <parameter key="first_name" value=""/> O <parameter key="last_name" value=""/> O <parameter key="middle_name" value=""/> O <parameter key="prefix" value=""/> O <parameter key="suffix" value=""/> O <parameter key="birth_date" value=""/> O ("yyyy-MM-dd") <parameter key="sex" value=""/> O (male,female,other) <parameter key="pregnancy" value=""/> O (not pregnant,possibly pregnant,definitively pregnant,unknown) empty string means not app <parameter key="insurance_number" value=""/> O <parameter key="address" value=""/> O <parameter key="town" value=""/> O <parameter key="postal_code" value=""/> O <parameter key="cellular_phone" value=""/> O <parameter key="home_phone" value=""/> O <parameter key="work_phone" value=""/> O <parameter key="comments" value=""/> O <parameter key="email" value=""/> O <parameter key="photo" value=""/> O <parameter key="kdis6_patient_directory" value=""/> O (used for import kdis6 images) <parameter key="images_imported" value=""/> C ("true/false", must be pair with kdis6_patient_directory) </patient> </trophy> """
  • 17.
    XML verify • Thesoap service output is xml string • You can use contains to verify simple value • But not easy to verify specific value
  • 18.
    XmlUnit • XML canbe used for just about anything so deciding if two documents are equal to each other isn't as easy as a character for character match public void testXPathValues() throws Exception { String myJavaFlavours = "<java-flavours><jvm current='some platforms'>1.1.x</jvm>" + "<jvm current='no'>1.2.x</jvm><jvm current='yes'>1.3.x</jvm>" + "<jvm current='yes' latest='yes'>1.4.x</jvm></java-flavours>"; assertXpathEvaluatesTo("1.4.x", "//jvm[@latest='yes']", myJavaFlavours); assertXpathEvaluatesTo("2", "count(//jvm[@current='yes'])", myJavaFlavours); assertXpathValuesEqual("//jvm[4]/@latest", "//jvm[4]/@current", myJavaFlavours); assertXpathValuesNotEqual("//jvm[2]/@current", "//jvm[3]/@current", myJavaFlavours); }
  • 19.
    Scala XML val ns= <foo><bar><baz/>Text</bar><bin/></foo> ns "foo" // => <foo><bar>...</bar><bin/></foo> ns "foo" "bar" // => <bar><baz/>Text</bar> val ns = <foo id="bar"/> ns "@id" // => Text(bar)
  • 20.
    JRuby REXML xml =File.read('posts.xml') puts Benchmark.measure { doc, posts = REXML::Document.new(xml), [] doc.elements.each('posts/post') do |p| posts << p.attributes End }
  • 21.
    Model Date verify •After execute the method you want to know every thing is correct.
  • 22.
    Solutions • DbUnit canalso help you to verify that your database data match an expected set of values. • Call hibernate Dao Directly • Verify by other business method
  • 23.
    Files verify • Customutile • public static void checkDuplicateFiles(File dir)
  • 24.
    Notification verify • AnActiveMQ client utile • It should run in other thread and subscript before call method • It should time out if no message received after long time
  • 25.
    Wait future notification "Thereshould have imageCreated notification after image is created " should { " ok " in { val srcPid = DataPrepare.createPatient val msg = future(ActiveMQ.receive("topic.imageCreated")) val imgId = DataPrepare.prepareImage(srcPid)._1 //wait a 3 second awaitAll(3000,msg) foreach{ v => v match { case Some(m) => { m.toString must contain (srcPid) m.toString must contain (imgId) } case None => 1 must_== 2 } } } }
  • 26.
  • 27.
    EasyMock public void testTransferShouldDebitSourceAccount(){ AccountController controller = new AccountController(); Account from = createMock(Account.class) Account to = createMock(Account.class) from.debit(42); replay(from); replay(to); controller.transfer(from,to,42); verify(from); }
  • 28.
    jMock Mockery context =new Mockery(); public void testTransferShouldDebitSourceAccount(){ AccountController controller = new AccountController(); Account from = context.mock(Account.class) Account to = context.mock(Account.class) context.checking(new Expectations() {{ oneOf(from).debit(42); }} controller.transfer(from,to,42); context.assertIsSatisfied(); }
  • 29.
    mockito public void testTransferShouldDebitSourceAccount(){ AccountController controller = new AccountController(); Account from = mock(Account.class) Account to = mock(Account.class) controller.transfer(from,to,42); verify(from).debit(42); }
  • 30.
    public void testTransferShouldDebitSourceAccount(){ AccountController controller = new AccountController(); Account from = createMock(Account.class) Account to = createMock(Account.class) from.debit(42); replay(from); replay(to); controller.transfer(from,to,42); verify(from); } Mockery context = new Mockery(); public void testTransferShouldDebitSourceAccount(){ AccountController controller = new AccountController(); Account from = context.mock(Account.class) Account to = context.mock(Account.class) context.checking(new Expectations() {{ oneOf(from).debit(42); }} controller.transfer(from,to,42); context.assertIsSatisfied(); } public void testTransferShouldDebitSourceAccount(){ AccountController controller = new AccountController(); Account from = mock(Account.class) Account to = mock(Account.class) controller.transfer(from,to,42); verify(from).debit(42); }
  • 31.
  • 32.
    Environment and Context Name Location Interaction DB Internal JDBC connect with hibernate ActiveMQ Internal socket,ActiveMQ library Demo External cmd,socket Config file External read/write file Registration table External system tool,reg Schedule External trigger 2D External cmd,socket Object Applications External cmd
  • 33.
    Unit testing styles •BDD • Better test code • It’s better not only for developer. If P.O. can read our test code is better • The test code should like specifics
  • 34.
    Traditional Status asserttest public void testAdd() { int num1 = 3; int num2 = 2; int total = 5; int sum = 0; sum = Math.add(num1, num2); assertEquals(sum, total); }
  • 35.
    BDD specifications style classHelloWorldSpec extends Specification { "The 'Hello world' string" should { "contain 11 characters" in { "Hello world" must have size(11) } "start with 'Hello'" in { "Hello world" must startWith("Hello") } "end with 'world'" in { "Hello world" must endWith("world") } } "The sum" should { “ equals total " in { val num1 = 2,num2 = 3, total = 5 Math.add(num1, num2) must equalsTo(total) } } }