JUnit Goodness


Published on

Presentation on some JUnit 4 Goodness that developers who came to JUnit at version 3 may have let slip under the radar. Parameterized tests, matcher assertions and the @Ignore annotations are presented in this slideshow.

Published in: Technology, Business
  • This is my xml file(One_inTwo.xml)
    Are you sure you want to  Yes  No
    Your message goes here
  • package concurrent;
    import java.net.URL;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junitext.XMLParameters;
    import org.openqa.selenium.By;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.remote.DesiredCapabilities;
    import org.openqa.selenium.remote.RemoteWebDriver;
    import org.junitext.runners.XMLParameterizedRunner;
    public class One_inTwo {
    public String browser1;
    public One_inTwo(String browser1) {
    public void test() throws Exception {
    WebDriver driver;
    URL server = new URL('http://localhost:8081/wd/hub');
    DesiredCapabilities capabilities = null;
    driver = new RemoteWebDriver(server, Common.getGridsettings(browser1, capabilities));
    WebElement search_editbox = driver.findElement(By.name('q'));
    WebElement search_button = driver.findElement(By.name('btnG'));

    Are you sure you want to  Yes  No
    Your message goes here
  • hello people
    I am getting the following error when working on XMLParameterized.class for getting input from an xml file

    java.lang.NoSuchMethodError: org.junit.internal.runners.MethodValidator.(Ljava/lang/Class;)V
    at org.junit.internal.runners.TestClassRunner.(TestClassRunner.java:26)
    at org.junitext.runners.XMLParameterizedRunner.(Unknown Source)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:31)
    at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:24)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
    at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:29)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
    at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:24)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.(JUnit4TestReference.java:32)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference.(JUnit4TestClassReference.java:25)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:41)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:31)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:452)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

    and i am using junit4.8.1.jar,junitext0.2.4.jar in windows XP OS

    and my code files are attached below.
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

JUnit Goodness

  1. 1. Solnet Solutions Ltd JUnit Goodness - October 2009
  2. 2. JUnit Goodness <ul><li>Parameterized Tests </li></ul><ul><li>Matcher Assertions </li></ul><ul><li>The @Ignore Annotation </li></ul>… Coming at you from all angles in JUnit 4
  3. 3. Parameterized Tests <ul><li>Why would you write a parameterized test? </li></ul><ul><li>How do you write a parameterized test? </li></ul>Parameterized tests are generic tests that run multiple times using a collection of test parameters.
  4. 4. Why Would You Write A Parameterized Tests <ul><li>Parameterized test are suitable for two types of test: </li></ul><ul><li>Tests that require different data in specific environments </li></ul><ul><li>Test that use multiple data sets (Data Driven testing) </li></ul><ul><li>Through the use of parameterized tests we can also eliminate the following JUnit test smells </li></ul><ul><li>Test cases that contain a test method for each test data combination </li></ul><ul><li>Test cases that loop over a collection of values </li></ul><ul><li>By implementing parameterized tests we are able to create tests in a DRY manner. </li></ul>
  5. 5. Eliminate JUnit Test Smell: Test cases that contain a test method for each test data combination <ul><li>@Test </li></ul><ul><li>public void testNegativeSpendingMoneyBudget() { </li></ul><ul><li>budget = new Budget(&quot;Negative Spending Budget&quot;, 1000.00, 560.00, 350.00, 100.00); </li></ul><ul><li>System. out .println(&quot;Testing budget spending money: &quot; + budget.getName()); </li></ul><ul><li>assertEquals (&quot;Spending Money is not what was expected&quot;, </li></ul><ul><li>-10.00, budget.getSpendingMoney(), 0.0); </li></ul><ul><li>} </li></ul><ul><li>...similar test cases exist for testNoSpendingMoneyBudget and testPositiveSpendingMoneyBudget </li></ul><ul><li>Issues with this JUnit test smell: </li></ul><ul><li>Each new test instance requires the addition of a new test method </li></ul><ul><li>Results in bloated test cases that reduce test suite maintainability </li></ul><ul><li>Duplicated test code breaks the DRY principle </li></ul><ul><li>In order to remove this smell we decide to refactor this test case…using a loop… </li></ul>
  6. 6. Eliminate JUnit Test Smell: Test cases that loop over a collection of values <ul><li>/** </li></ul><ul><li>* Loop Test - The main problem with this kind of test is that if 1 test </li></ul><ul><li>* fails the loop does not complete, so not all test instances are run. </li></ul><ul><li>**/ </li></ul><ul><li>@Test </li></ul><ul><li>public void testSpendingMoney() { </li></ul><ul><li>for (Budget budget: budgets ) { </li></ul><ul><li>System. out .println(&quot;Testing budget spending money: &quot; + budget.getName()); </li></ul><ul><li>assertEquals (&quot;Spending Money is not what was expected&quot;, </li></ul><ul><li>expectedSpendingMoney .get(budget.getName()).doubleValue(), </li></ul><ul><li>budget.getSpendingMoney(), 0.0); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>Issues with this JUnit test smell: </li></ul><ul><li>Single test failure will terminate the loop </li></ul><ul><li>Not all test instance values will be run if a failure occurs </li></ul><ul><li>No straightforward way to tell which test failed from failure message </li></ul>
  7. 7. More Reasons To Consider Parameterized Tests <ul><li>What happens when a new type of test is required when using either of the previous JUnit test smells? </li></ul><ul><li>What happens if the class methods under test are renamed or refactored? How quickly can the test be refactored to be back up and running? </li></ul><ul><li>What work would be involved to change the tests based on specific test environments? </li></ul><ul><li>How simple is it to change the data set being used for testing – for Data Driven testing? </li></ul>
  8. 8. How Do You Write A Parameterized Test <ul><li>Create a generic test method decorated with the @Test annotation </li></ul><ul><li>Create a static feeder method that returns a Collection type and decorate it with the @Parameters annotation </li></ul><ul><li>Create class members for the parameter types required in generic test methods </li></ul><ul><li>Create a constructor that takes the test parameter types and initializes the relevant class members </li></ul><ul><li>Specify that the test case should be run using the Parameterized class via the @RunWith annotation </li></ul>… Follow these 5 simple steps…
  9. 9. Parameterized Tests Considerations <ul><li>When using parameterized tests keep the following in mind: </li></ul><ul><li>An instance of the enclosing class is created for each test run </li></ul><ul><li>Keep non-parameterized tests out of the parameterized test class </li></ul><ul><li>Identification of any test instance failures is not straightforward </li></ul><ul><li>Where are we getting the parameterized test data from </li></ul>
  10. 10. Named Parameterized Test Extension <ul><li>Simplify test failure identification through a custom named extension </li></ul><ul><li>Extend the Suite test runner. </li></ul><ul><li>Duplicate the private TestClassRunnerForParameters </li></ul><ul><li>Update the getName() and testName() overriden methods with the identification details required </li></ul><ul><li>Ensure that the Parameters annotation used is from the extended implementation </li></ul>
  11. 11. XML Data Parameterized Test Extension <ul><li>Based on JUext (JUnit Extensions) XMLParameterizedRunner </li></ul><ul><li>JUnit extension exists, but does not work out of the box </li></ul><ul><li>Generate a custom XMLParameterized implementation </li></ul><ul><li>Similar implementation to NamedParamertized test extension </li></ul><ul><li>Use a ParameterSet instead of a List<Object>[] </li></ul><ul><li>getParametersList() method does the XML file look up </li></ul><ul><li>JUnit Extension XML Parameter limited parameter digester </li></ul><ul><li>Able to create bean object instances – similar to Spring (Budget) </li></ul><ul><li>Added double to DigesterParameterFactory object rules </li></ul><ul><li>data.xml file contains the test data </li></ul>
  12. 12. Matcher Assertions <ul><li>Matcher assertions match object and values and composite matcher values. (Original implemented in JMock and integrated into JUnit) </li></ul><ul><li>Core Matchers (Hamcrest) </li></ul><ul><li>allOf(), any(), anyOf(), anything(), describedAs(), equalTo(), instanceOf(), is(), not(), notNullValue, nullValue(), sameInstance() </li></ul><ul><li>JUnit Matcher </li></ul><ul><li>both(), containsString(), either(), everyItem(), hasItem(), hasItems() </li></ul>What are matcher assertions?
  13. 13. Matcher Assertions <ul><li>Reasons to use the matcher assertions? </li></ul><ul><li>More readable </li></ul><ul><li>Improved readability of failure messages </li></ul><ul><li>Matcher combinations/List matchers </li></ul><ul><li>Custom matchers </li></ul>assertThat([value], [matcher statement]);
  14. 14. Matchers – Readable <ul><li>assertThat(budget.getName(), is(“Budget Name”)) </li></ul><ul><li>- subject, verb, object </li></ul><ul><li>- “Assert that the budget’s name is ‘Budget Name’” </li></ul><ul><li>assertEquals(“Budget Name”, budget.getName()) </li></ul><ul><li>- verb, object, subject </li></ul><ul><li>- “Assert equals is ‘Budget Name’ the budget’s name” </li></ul><ul><li>assertThat(budget.getIncome, is(1000.00) </li></ul><ul><li>- “Assert that the budget’s income is 1000.00” </li></ul><ul><li>assertEquals(1000.00, budget.getIncome()) </li></ul><ul><li>- “Assert equals is 1000.00 the budget’s income” </li></ul>
  15. 15. Matchers – Readable Failure Messages <ul><li>assertThat(budget.getName(), </li></ul><ul><ul><ul><li>is(“Not Negative Spending Budget”)) </li></ul></ul></ul><ul><li>- Failure Message </li></ul><ul><li>java.lang.AssertionError </li></ul><ul><li>Expected: is “Not Negative Spending Budget” </li></ul><ul><li>got: “Negative Spending Budget” </li></ul><ul><li>assertEquals(“Not Negative Spending Budget”, </li></ul><ul><ul><ul><li>budget.getName()) </li></ul></ul></ul><ul><li>- Failure Message </li></ul><ul><li>org.junit.ComparisonFailure: expected: <N[ot N]egative Spending Budget> but was: <N[]egative Spending Budget> </li></ul>
  16. 16. Matchers – Combinations/Lists/Custom <ul><li>Combination Matcher Assertions: </li></ul><ul><li>Combinations can be used to negate matches </li></ul><ul><li>assertThat(budget.getIncome(), is(not(equalTo(800.00)))) </li></ul><ul><li>Combinations can be used to combine matchers </li></ul><ul><li>assertThat(budget.getIncome(), both(notNullValue()).and(is(1000.00))) </li></ul><ul><li>Lists and Custom Matchers: </li></ul><ul><li>List Matchers </li></ul><ul><li>assertThat(budgets, hasItem(negativeSpendingBudget)) </li></ul><ul><li>Custom Matchers </li></ul><ul><li>assertThat(negativeSpendingBudget, hasIncomeOf(1000.00)) </li></ul>
  17. 17. Matchers – Custom Matchers <ul><li>Extend Matcher implementation </li></ul><ul><li>public class HasIncomeOf extends BaseMatcher<Object> </li></ul><ul><li>Matcher implementations: </li></ul><ul><li>BaseMatcher (Hamcrest) </li></ul><ul><li>TypeSafetyMatcher (JUnit Matcher extends BaseMatcher) </li></ul><ul><li>CombinableMatcher (JUnit Matcher extends BaseMatcher) </li></ul><ul><li>SubstringMatcher (JUnit Matcher extends TypeSafeMatcher) </li></ul><ul><li>Create a static convenience factory method for the matcher </li></ul><ul><li>- factory method name is important as this is the static test method </li></ul><ul><li>@Factory </li></ul><ul><li>public static Matcher<Object> hasIncomeOf(D ouble income) { </li></ul><ul><li>return new HasIncomeOf(income); </li></ul><ul><li>} </li></ul><ul><li>Implement the match method for the matcher implementation </li></ul><ul><li>BaseMatcher = boolean matches(Object item) </li></ul><ul><li>TypeSafetyMatcher = boolean matchesSafely(T item) </li></ul>
  18. 18. Matchers – Custom Matchers <ul><li>Implement the describeTo(Description description) method to improve failure messages </li></ul><ul><li>description.appendText(&quot;has income of &quot;).appendValue( this .income) </li></ul><ul><li>Import the static convenience factory method to use the matcher </li></ul><ul><li>import static nz.co.solnetsolutions.custom.matchers.HasIncomeOf.hasIncomeOf </li></ul><ul><li>… </li></ul><ul><li>assertThat ( negativeSpendingBudget , hasIncomeOf (900.00)); </li></ul>
  19. 19. The @Ignore Annotation <ul><li>Use of this annotation means that there should be no need to comment out tests (when committing code) </li></ul><ul><li>Can be used to temporarily disable a test or group of tests (during code refactoring, place holder) </li></ul><ul><li>Can be used at the class level – in this case no tests will be executed </li></ul><ul><li>Native JUnit 4 test runners should report the number of ignored tests alongside tests run and failures </li></ul><ul><li>An optional default parameter for recording the reason why a test/group of tests is being ignored </li></ul><ul><li>@Ignore(“Reason for ignoring this test!”) </li></ul>
  20. 20. Summary <ul><li>Parameterized Tests </li></ul><ul><ul><li>Use to eliminate DRY test code smells </li></ul></ul><ul><ul><li>Use when writing data-driven tests or tests that require different data in different environments </li></ul></ul><ul><ul><li>Create generic tests that make use of a static factory method decorated with the @Parameters annotation </li></ul></ul><ul><ul><li>Create class members and constructor and decorate with the @RunWith annotation </li></ul></ul><ul><ul><li>Extensible: Named Parameterized Test & XML Data Driven Parameterized Test </li></ul></ul><ul><li>Matcher Assertions </li></ul><ul><ul><li>Read more naturally [ assertThat(a, is(3) ] </li></ul></ul><ul><ul><li>More readable failure messages [ Expected is: 3 got: 2 ] </li></ul></ul><ul><ul><li>Can use combinations of matchers [ assertThat(a, both(notNullValue()).and(is(3)))] </li></ul></ul><ul><ul><li>List matchers [ assertThat(myList, hasItem(item1)) </li></ul></ul><ul><ul><li>Custom matchers </li></ul></ul><ul><li>@Ignore Annotation </li></ul><ul><ul><li>No more ‘commented out’ tests! </li></ul></ul><ul><ul><li>Temporarily disable tests or groups of tests </li></ul></ul><ul><ul><li>Native JUnit runners will report the tests as ‘ignored’ </li></ul></ul><ul><ul><li>Good practice to include the reason for the test being ignored in the @Ignore annotation </li></ul></ul>
  21. 21. References <ul><li>Giudici, Fabrizio - JUnit: A Little Beyond @Test, @Before, @After ( http://netbeans.dzone.com/articles/junit-little-beyond-test-after ) </li></ul><ul><li>Hamcrest ( http:// code.google.com/p/hamcrest / ) </li></ul><ul><li>JMock ( http://www.jmock.org ) </li></ul><ul><li>JUnit release notes ( http://junit.sourceforge.net/doc/ReleaseNotes4.4.html ) </li></ul><ul><li>JUnit API’s </li></ul><ul><li>JUext ( http:// junitext.sourceforge.net / ) </li></ul><ul><li>Test Early Blog ( http://www.testearly.com ) </li></ul><ul><li>Walnes, Joe – Flexible JUnit assertions with assertThat() ( http://joe.truemesh.com/blog/000511.html ) </li></ul>