Important Announcement
PubHTML5 Scheduled Server Maintenance on (GMT) Sunday, June 26th, 2:00 am - 8:00 am.
PubHTML5 site will be inoperative during the times indicated!

Home Explore Java.Power.Tools

Java.Power.Tools

Published by jack.zhang, 2014-07-28 04:28:37

Description: Java Power Tools
Overview
All true craftsmen need the best tools to do their finest work, and programmers are no
different. Java Power Tools delivers 30 open source tools designed to improve the
development practices of Java developers in any size team or organization. Each chapter
includes a series of short articles about one particular tool -- whether it's for build systems,
version control, or other aspects of the development process -- giving you the equivalent
of 30 short reference books in one package. No matter which development method your
team chooses, whether it's Agile, RUP, XP, SCRUM, or one of many others available, Java
Power Tools provides practical techniques and tools to help you optimize the process. The
book discusses key Java development problem areas and best practices, and focuses on
open source tools that can help increase productivity in each area of the development
cycle, including:
 Build tools including Ant and Maven 2
 Version control tools

Search

Read the Text Version

Java Power Tools Alternatively, you can periodically poll the queue for new messages using the pollResult() method. 500

Java Power Tools Part 4: Unit Testing The next moment the day became very bothering indeed, because Pooh was so busy not looking where he was going that he stepped on a piece of the Forest which had been left out by mistake. —\"A Search is Organized, and Piglet Nearly Meets the Heffalump Again,\" The House at Pooh Corner, A. A. Milne Software development is very much a trial-and-error process, and it pays to proceed cautiously, little-by-little. This is why good testing is an essential part of the software development process. Although in practice it is often neglected, few developers today would deny the fundamental value of proper testing. Unit tests, especially when used in conjunction with modern agile development processes and techniques such as Test-Driven Development, have the potential to drastically increase the quality and reliability of your code. Unit tests are also a very effective means of detecting regressions, especially when Continuous Integration techniques (Chapters Chapter 5, Chapter 6, Chapter 7) is being used. Whether you are adding functionality or refactoring existing code, a comprehensive set of unit tests provide a quick way of verifying that no existing functionality has been broken by recent changes. Unit testing basically involves writing test cases to ensure that your classes function correctly. Unit tests are typically fairly low-level and modular—ideally, you should be able to execute a unit test in isolation, and not depend on any other test cases to be run beforehand. In other words, your tests should be able to be executed in any order, or individually, and still work correctly. Another important best practice regarding unit tests is that unit test should leave the system in the same state as it was in before the test. For example, if you are testing a DAO class, your tests may well insert, update, and delete data in the database, but once the test has finished, the database should be in the same state as before the test was started. This is not always easy, as a failed test may well leave your environment in an unstable state. Developers often need to write special code (generally known as \"fixture code\") designed to set up a clean test environment before testing and to tidy up afterward. Although it is possible to write unit tests entirely from scratch, unit testing frameworks make things at lot easier. By providing a simple, well-understood framework in which to write your tests, libraries such as JUnit and TestNG let developers concentrate on writing high quality unit tests. Testing frameworks also make it easier to organize your tests, to selectively run individual tests, to report on test results, and to write supporting fixture code. 501

Java Power Tools Many books and articles have been written on unit testing, and on recommended testing practices in general. In this section, we will look at tools and techniques that can improve your productivity when it comes to testing your application. We will also be looking at that vital complement to unit testing, code coverage, as well as at one of the leading open source code coverage tools, Cobertura. Code coverage tools help you verify what parts of your code are being tested by your unit tests, and, more important, what parts aren't. Although code coverage statistics offer little guarantee that your code is being tested well, they are certainly better than nothing and can give valuable tips on any shady areas of code that have been left untested. And it is well known that bugs like to accumulate in the shadows. Chapter 10. Testing Your Code with JUnit JUnit 3.8 and JUnit 4 Unit Testing with JUnit 4 Setting Up and Optimizing Your Unit Test Cases Simple Performance Testing Using Timeouts Checking for Exceptions the Easy Way Using Parameterized Tests Using assertThat and the Hamcrest Library JUnit 4 Theories Using JUnit 4 with Maven 2 Using JUnit 4 with Ant Selectively Running JUnit 4 Tests in Ant Integration Tests Using JUnit 4 in Eclipse 10.1. JUnit 3.8 and JUnit 4 JUnit was a groundbreaking piece of software in its day, and there are many, many useful JUnit extensions that help with unit testing in specialized areas and that still rely on the JUnit 3.x approach. We will look at a few of them later on in the book. This section is a brief refresher on 502

Java Power Tools JUnit 3.8, for future reference and to better understand the changes brought by newer frameworks such as JUnit 4 and TestNG (Chapter 20). In JUnit 3, you write unit tests in special Java classes, called test cases. All JUnit 3 test cases must extend the TestCase class. You write unit tests as methods of these classes, following a special naming convention: test methods must return void, take no parameters, and start with the word \"test.\" Your test classes usually also follow a particular naming convention, such as ending with the word Test. Here is a simple Unit 3.8 test class that tests a class that calculates GST (\"Goods and Services Tax,\" also known as a \"Value Added Tax\" in some countries). Suppose that the standard GST rate is 12.5 percent. Our unit test class might look like this: public class PriceCalculatorTest extends TestCase { public void testCalculateGST() { calculator = new PriceCalculator(); double amountWithGst = calculator.calculatePriceWithGST(100.00); assertEquals(\"Standard GST is 12.5%\", 112.50, amountWithGst, 0.0); } } The TestCase base class comes with a large number of assert methods: assertEquals(), assertTrue(), assertNotNull(), and many more. These make up the core of your unit tests, since they are what you use to actually perform your tests. You use the assert methods to check your obtained results against the expected results. You can optionally provide a message as the first parameter of your asserts, which can help to make it easier to identify the error when you have a lot of unit tests to run. You can override the setUp() and tearDown()methods (be careful of the capital letters!) to define initialization and housekeeping code that will be run, respectively, before and after each test. For example, if we have many test cases using the calculator object, we might want to create it only once in the setUp() method: public class PriceCalculatorTest extends TestCase { PriceCalculator calculator; protected void setUp() throws Exception { calculator = new PriceCalculator(); } public void testCalculateGST() { double amountWithGst = calculator.calculatePriceWithGST(100.00); assertEquals(\"Standard GST is 12.5%\", 112.50, amountWithGst, 0.0); } // More tests with the calculator object 503

Java Power Tools } There is actually more to JUnit 3 than this, but you should now be familiar enough with the JUnit 3 architecture, to understand the innovations brought by the newer frameworks, and to use the JUnit 3 extensions that we discuss in other chapters. JUnit 4 is usually preferable, but 3.8 is still widely used, and many plug-ins still haven't been updated for JUnit 4. In the remainer of this chapter, we will refer exclusively to JUnit 4. Chapter 10. Testing Your Code with JUnit The next moment the day became very bothering indeed, because Pooh was so busy not looking where he was going that he stepped on a piece of the Forest which had been left out by mistake. —\"A Search is Organized, and Piglet Nearly Meets the Heffalump Again,\" The House at Pooh Corner, A. A. Milne Software development is very much a trial-and-error process, and it pays to proceed cautiously, little-by-little. This is why good testing is an essential part of the software development process. Although in practice it is often neglected, few developers today would deny the fundamental value of proper testing. Unit tests, especially when used in conjunction with modern agile development processes and techniques such as Test-Driven Development, have the potential to drastically increase the quality and reliability of your code. Unit tests are also a very effective means of detecting regressions, especially when Continuous Integration techniques (Chapters Chapter 5, Chapter 6, Chapter 7) is being used. Whether you are adding functionality or refactoring existing code, a comprehensive set of unit tests provide a quick way of verifying that no existing functionality has been broken by recent changes. Unit testing basically involves writing test cases to ensure that your classes function correctly. Unit tests are typically fairly low-level and modular—ideally, you should be able to execute a unit test in isolation, and not depend on any other test cases to be run beforehand. In other words, your tests should be able to be executed in any order, or individually, and still work correctly. Another important best practice regarding unit tests is that unit test should leave the system in the same state as it was in before the test. For example, if you are testing a DAO class, your tests may well insert, update, and delete data in the database, but once the test has finished, the database should be in the same state as before the test was started. This is not always easy, as a failed test may well leave your environment in an unstable state. Developers often need to write special code (generally known as \"fixture code\") designed to set up a clean test environment before testing and to tidy up afterward. 504

Java Power Tools Although it is possible to write unit tests entirely from scratch, unit testing frameworks make things at lot easier. By providing a simple, well-understood framework in which to write your tests, libraries such as JUnit and TestNG let developers concentrate on writing high quality unit tests. Testing frameworks also make it easier to organize your tests, to selectively run individual tests, to report on test results, and to write supporting fixture code. Many books and articles have been written on unit testing, and on recommended testing practices in general. In this section, we will look at tools and techniques that can improve your productivity when it comes to testing your application. We will also be looking at that vital complement to unit testing, code coverage, as well as at one of the leading open source code coverage tools, Cobertura. Code coverage tools help you verify what parts of your code are being tested by your unit tests, and, more important, what parts aren't. Although code coverage statistics offer little guarantee that your code is being tested well, they are certainly better than nothing and can give valuable tips on any shady areas of code that have been left untested. And it is well known that bugs like to accumulate in the shadows. Chapter 10. Testing Your Code with JUnit JUnit 3.8 and JUnit 4 Unit Testing with JUnit 4 Setting Up and Optimizing Your Unit Test Cases Simple Performance Testing Using Timeouts Checking for Exceptions the Easy Way Using Parameterized Tests Using assertThat and the Hamcrest Library JUnit 4 Theories Using JUnit 4 with Maven 2 Using JUnit 4 with Ant Selectively Running JUnit 4 Tests in Ant Integration Tests Using JUnit 4 in Eclipse 505

Java Power Tools 10.1. JUnit 3.8 and JUnit 4 JUnit was a groundbreaking piece of software in its day, and there are many, many useful JUnit extensions that help with unit testing in specialized areas and that still rely on the JUnit 3.x approach. We will look at a few of them later on in the book. This section is a brief refresher on JUnit 3.8, for future reference and to better understand the changes brought by newer frameworks such as JUnit 4 and TestNG (Chapter 20). In JUnit 3, you write unit tests in special Java classes, called test cases. All JUnit 3 test cases must extend the TestCase class. You write unit tests as methods of these classes, following a special naming convention: test methods must return void, take no parameters, and start with the word \"test.\" Your test classes usually also follow a particular naming convention, such as ending with the word Test. Here is a simple Unit 3.8 test class that tests a class that calculates GST (\"Goods and Services Tax,\" also known as a \"Value Added Tax\" in some countries). Suppose that the standard GST rate is 12.5 percent. Our unit test class might look like this: public class PriceCalculatorTest extends TestCase { public void testCalculateGST() { calculator = new PriceCalculator(); double amountWithGst = calculator.calculatePriceWithGST(100.00); assertEquals(\"Standard GST is 12.5%\", 112.50, amountWithGst, 0.0); } } The TestCase base class comes with a large number of assert methods: assertEquals(), assertTrue(), assertNotNull(), and many more. These make up the core of your unit tests, since they are what you use to actually perform your tests. You use the assert methods to check your obtained results against the expected results. You can optionally provide a message as the first parameter of your asserts, which can help to make it easier to identify the error when you have a lot of unit tests to run. You can override the setUp() and tearDown()methods (be careful of the capital letters!) to define initialization and housekeeping code that will be run, respectively, before and after each test. For example, if we have many test cases using the calculator object, we might want to create it only once in the setUp() method: public class PriceCalculatorTest extends TestCase { PriceCalculator calculator; protected void setUp() throws Exception { calculator = new PriceCalculator(); } 506

Java Power Tools public void testCalculateGST() { double amountWithGst = calculator.calculatePriceWithGST(100.00); assertEquals(\"Standard GST is 12.5%\", 112.50, amountWithGst, 0.0); } // More tests with the calculator object } There is actually more to JUnit 3 than this, but you should now be familiar enough with the JUnit 3 architecture, to understand the innovations brought by the newer frameworks, and to use the JUnit 3 extensions that we discuss in other chapters. JUnit 4 is usually preferable, but 3.8 is still widely used, and many plug-ins still haven't been updated for JUnit 4. In the remainer of this chapter, we will refer exclusively to JUnit 4. Section 10.1. JUnit 3.8 and JUnit 4 The next moment the day became very bothering indeed, because Pooh was so busy not looking where he was going that he stepped on a piece of the Forest which had been left out by mistake. —\"A Search is Organized, and Piglet Nearly Meets the Heffalump Again,\" The House at Pooh Corner, A. A. Milne Software development is very much a trial-and-error process, and it pays to proceed cautiously, little-by-little. This is why good testing is an essential part of the software development process. Although in practice it is often neglected, few developers today would deny the fundamental value of proper testing. Unit tests, especially when used in conjunction with modern agile development processes and techniques such as Test-Driven Development, have the potential to drastically increase the quality and reliability of your code. Unit tests are also a very effective means of detecting regressions, especially when Continuous Integration techniques (Chapters Chapter 5, Chapter 6, Chapter 7) is being used. Whether you are adding functionality or refactoring existing code, a comprehensive set of unit tests provide a quick way of verifying that no existing functionality has been broken by recent changes. Unit testing basically involves writing test cases to ensure that your classes function correctly. Unit tests are typically fairly low-level and modular—ideally, you should be able to execute a unit test in isolation, and not depend on any other test cases to be run beforehand. In other words, your tests should be able to be executed in any order, or individually, and still work correctly. Another important best practice regarding unit tests is that unit test should leave the system in the same state as it was in before the test. For example, if you are testing a DAO 507

Java Power Tools class, your tests may well insert, update, and delete data in the database, but once the test has finished, the database should be in the same state as before the test was started. This is not always easy, as a failed test may well leave your environment in an unstable state. Developers often need to write special code (generally known as \"fixture code\") designed to set up a clean test environment before testing and to tidy up afterward. Although it is possible to write unit tests entirely from scratch, unit testing frameworks make things at lot easier. By providing a simple, well-understood framework in which to write your tests, libraries such as JUnit and TestNG let developers concentrate on writing high quality unit tests. Testing frameworks also make it easier to organize your tests, to selectively run individual tests, to report on test results, and to write supporting fixture code. Many books and articles have been written on unit testing, and on recommended testing practices in general. In this section, we will look at tools and techniques that can improve your productivity when it comes to testing your application. We will also be looking at that vital complement to unit testing, code coverage, as well as at one of the leading open source code coverage tools, Cobertura. Code coverage tools help you verify what parts of your code are being tested by your unit tests, and, more important, what parts aren't. Although code coverage statistics offer little guarantee that your code is being tested well, they are certainly better than nothing and can give valuable tips on any shady areas of code that have been left untested. And it is well known that bugs like to accumulate in the shadows. Chapter 10. Testing Your Code with JUnit JUnit 3.8 and JUnit 4 Unit Testing with JUnit 4 Setting Up and Optimizing Your Unit Test Cases Simple Performance Testing Using Timeouts Checking for Exceptions the Easy Way Using Parameterized Tests Using assertThat and the Hamcrest Library JUnit 4 Theories Using JUnit 4 with Maven 2 508

Java Power Tools Using JUnit 4 with Ant Selectively Running JUnit 4 Tests in Ant Integration Tests Using JUnit 4 in Eclipse 10.1. JUnit 3.8 and JUnit 4 JUnit was a groundbreaking piece of software in its day, and there are many, many useful JUnit extensions that help with unit testing in specialized areas and that still rely on the JUnit 3.x approach. We will look at a few of them later on in the book. This section is a brief refresher on JUnit 3.8, for future reference and to better understand the changes brought by newer frameworks such as JUnit 4 and TestNG (Chapter 20). In JUnit 3, you write unit tests in special Java classes, called test cases. All JUnit 3 test cases must extend the TestCase class. You write unit tests as methods of these classes, following a special naming convention: test methods must return void, take no parameters, and start with the word \"test.\" Your test classes usually also follow a particular naming convention, such as ending with the word Test. Here is a simple Unit 3.8 test class that tests a class that calculates GST (\"Goods and Services Tax,\" also known as a \"Value Added Tax\" in some countries). Suppose that the standard GST rate is 12.5 percent. Our unit test class might look like this: public class PriceCalculatorTest extends TestCase { public void testCalculateGST() { calculator = new PriceCalculator(); double amountWithGst = calculator.calculatePriceWithGST(100.00); assertEquals(\"Standard GST is 12.5%\", 112.50, amountWithGst, 0.0); } } The TestCase base class comes with a large number of assert methods: assertEquals(), assertTrue(), assertNotNull(), and many more. These make up the core of your unit tests, since they are what you use to actually perform your tests. You use the assert methods to check your obtained results against the expected results. You can optionally provide a message as the first parameter of your asserts, which can help to make it easier to identify the error when you have a lot of unit tests to run. You can override the setUp() and tearDown()methods (be careful of the capital letters!) to define initialization and housekeeping code that will be run, respectively, before and after each test. For example, if we have many test cases using the calculator object, we might want to create it only once in the setUp() method: 509

Java Power Tools public class PriceCalculatorTest extends TestCase { PriceCalculator calculator; protected void setUp() throws Exception { calculator = new PriceCalculator(); } public void testCalculateGST() { double amountWithGst = calculator.calculatePriceWithGST(100.00); assertEquals(\"Standard GST is 12.5%\", 112.50, amountWithGst, 0.0); } // More tests with the calculator object } There is actually more to JUnit 3 than this, but you should now be familiar enough with the JUnit 3 architecture, to understand the innovations brought by the newer frameworks, and to use the JUnit 3 extensions that we discuss in other chapters. JUnit 4 is usually preferable, but 3.8 is still widely used, and many plug-ins still haven't been updated for JUnit 4. In the remainer of this chapter, we will refer exclusively to JUnit 4. Section 10.2. Unit Testing with JUnit 4 When it comes to unit testing frameworks, JUnit is the de facto standard. It is widely used and known, and has many useful extensions for more specialized testing. JUnit, originally written by Kent Beck and Erich Gamma, is widely recognized as a monumental piece of software that greatly contributed to the popularity (at least in theory) of decent unit testing practices in Java. However, over the last few years, the basic API has not evolved a great deal, and some other different and innovative testing frameworks such as TestNG (see Chapter 20) have emerged. JUnit 3 imposes many constraints which are no longer justified in the world of Java 5, annotations and IOC programming. In JUnit 3, test classes need to extend a JUnit base class, and tests need to respect a special naming convention: you cannot use any old Java class as a test class. JUnit 3 test classes are initialised each time a test is executed, which makes it harder to refactorise and optimize test code. There is no support for data-driven testing (running your tests against externally provided data). It also lacks features such as dependencies between tests, and test groups. JUnit 4 is a major rewrite of the JUnit API, which aims at taking advantage of the progress in Java technology over the pass few years. It is simpler, easier, and more flexible to use than its predecessor, with a few new features to boot! It introduces a lot of new features that can make writing your unit tests easier, such as the use of annotations and more 510

Java Power Tools flexible test class initialization. In JUnit 4, a test can be any old POJO class, and test methods don't need to respect any particular naming convention. Let's see how our tax calculator tests (see Section 10.1) would look in JUnit 4: import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; public class PriceCalculatorTest { @Test public void calculateStandardGST() { PriceCalculator calculator = new PriceCalculator(); double gst = calculator.calculatePriceWithGST(100.00); assertEquals(gst, 112.50 , 0.0); } @Test public void calculateReducedGST() { PriceCalculator calculator = new PriceCalculator(); double gst = calculator.calculatePriceWithReducedGST(100.00); assertEquals(gst, 105.00 , 0.0); } } The first thing to notice is that, unlike test classes in JUnit 3, a JUnit 4 test case does not need to extend any particular class. JUnit 4, like TestNG, uses annotations to indicate which methods should be treated as unit tests. Any method marked by the @Test annotation is considered to be a unit test. There is no particular naming convention (tests no longer need to be called testThis or testThat), although the methods still do need to return void and take no parameters. In theory, you could even place your unit tests in the same class as the code you are testing, although in practice it is probably a good idea to keep them separate. The org.junit.Assert class contains the old JUnit 3.x asserts we've all come to know and love. In JUnit 3, the assert methods were defined in the TestCase class, the base class of all JUnit test classes, and so could be used in any JUnit test. Not so in JUnit 4, where test classes no longer need to be derived from TestCase. To avoid much heartache and gnashing of teeth, you can do a static import on this class (as shown here) so that you can use these asserts (assertEquals, assertNotNull, and so on) in exactly the same way as in your old JUnit 3.x unit tests. Alternatively, you can also use Java 5 assert statements: assert (gst == 100*PriceCalculator.DEFAULT_GST_RATE); 511

Java Power Tools This may look nicer, but there is a hitch: Java will blissfully ignore your asserts unless you use the -ea (enable assertions) command-line option. Section 10.3. Setting Up and Optimizing Your Unit Test Cases As with as any other code, unit tests need to be coded efficiently and refactored where necessary. JUnit 4 provides a couple of annotations that can help you out here. The @Before annotation indicates a method that needs to be called before each test, effectively replacing the setup() method of JUnit 3.x. You can also use the @After annotation to indicate any cleanup methods that need to be run after each test. Here, the initialize() method will be called before, and tidyup() after, each unit test: Code View: import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; public class PriceCalculatorTest { private PriceCalculator calculator; @Before public void initialize() { calculator = new PriceCalculator(); } @Test public void calculateStandardGST() { PriceCalculator calculator = new PriceCalculator(); double gst = calculator.calculatePriceWithGST(100.00); assertEquals(gst, 112.50 , 0.0); } @Test public void calculateReducedGST() { PriceCalculator calculator = new PriceCalculator(); double gst = calculator.calculatePriceWithReducedGST(100.00); assertEquals(gst, 105 , 0.0); } @After public void tidyup() { calculator.close(); 512

Java Power Tools calculator = null; } } However, this may still not be optimal. JUnit also provides a few other annotations which you can use to improve things further. Sometimes, for the sake of efficiency, you would like to be able to be able to set up some resources before you run any of the unit tests in a given class, and then clean up afterward. You can do just that with the @BeforeClass and @AfterClass annotations. Methods annotated with @BeforeClass will be invoked just once, before any of the unit tests are executed. And, as you would expect, methods annotated with @AfterClass are executed only when all of the tests have been completed. In the above example, the calculator object should be created only once, at the start of the unit tests, and closed only after all of the tests have been completed. We might add a reset() method, called before each unit test, to reinitialize the calculator each time. Here is what our optimized unit test class might look like: Code View: import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; public class PriceCalculatorTest { private PriceCalculator calculator; @BeforeClass public void initialize() { calculator = new PriceCalculator(); } @Before public void resetCalculator() { calculator.reset(); } @Test public void calculateStandardGST() { PriceCalculator calculator = new PriceCalculator(); double gst = calculator.calculatePriceWithGST(100.00); assertEquals(gst, 112.50 , 0.0); } @Test public void calculateReducedGST() { PriceCalculator calculator = new PriceCalculator(); double gst = calculator.calculatePriceWithReducedGST(100.00); 513

Java Power Tools assertEquals(gst, 105 , 0.0); } @AfterClass public void tidyup() { calculator.close(); } } Section 10.4. Simple Performance Testing Using Timeouts A very simple type of performance testing involves making sure that a particular test always executes within a certain timeframe. This can also be useful for database queries using O/R mapping tools such as Hibernate. Basic errors in Hibernate mapping files, for example, can result in very poor response times, even for relatively simple queries. Although a normal unit test wouldn't pick this up, a test with a timeout would. This sort of check also works nicely for detecting infinite loops, although it is of course harder to know which parts of your code are likely to contain infinite loops.... This technique is directly integrated into the @Test annotation, which allows you to set an upper limit on the amount of time a test may run without failing. To do this, you specify the timeout parameter of the @Test annotation (in milliseconds), as shown here: @Test(timeout=100) public void lookupGST() { double gst = calculator.lookupRateForYear(2006); assertEquals(gst, GST_RATE_IN_2006 , 0.0); } Now, if the query takes more than 100 milliseconds, the test will fail: Testsuite: com.wakaleo.jpt.alexandria.services.PriceCalculatorTest Tests run: 3, Failures: 0, Errors: 1, Time elapsed: 0.136 sec Testcase: calculateStandardGST took 0.009 sec Testcase: lookupGST took 0.128 sec Caused an ERROR test timed out after 100 milliseconds java.lang.Exception: test timed out after 100 milliseconds For some critial, high-performance methods, you might want to check that the classes perform with acceptable throughput. Of course, the lower the timeout value, the higher 514

Java Power Tools the chances are that some outside factor might slow down your tests and that your tests might timeout incorrectly. For example, in the following test case, we check that on average the calculateInterest() method never takes more than a millisecond to run: Code View: @Test(timeout=50) public void perfTestCalculateInterest() { InterestCalculator calc = new InterestCalculatorImpl(); for(int i = 0 ; i < 50; i++) { calc.calculateInterest(principal, interestRate, startDate, periodInDays); } } This type of test is just a reality check to make sure your methods are not excessively slow, so don't be too demanding. Section 10.5. Checking for Exceptions the Easy Way Sometimes you want to check that an exception is correctly thrown under certain circumstances. In JUnit 3.x, this is a fairly laborious task involving catching the exception and asserting success in this case and failure otherwise. In JUnit 4, you can use the expected parameter in the @Test annotation to the exception that should be thrown if all goes according to plan. In the following (somewhat contrived) example, we require the application to go through an IllegalArgumentException if the year is less than some arbitrary year. In JUnit 4, we can check this fairly easily as shown here: @Test(expected = IllegalArgumentException.class) public void lookupIllegalGSTYear() { double gst = calculator.lookupRateForYear(1066); } Now, if this method doesn't throw an IllegalArgumentException, the test will fail: Testsuite: com.wakaleo.jpt.alexandria.services.PriceCalculatorTest Tests run: 3, Failures: 1, Errors: 0, Time elapsed: 0.114 sec Testcase: calculateStandardGST took 0.009 sec Testcase: lookupGST took 0.01 sec Testcase: lookupIllegalGSTYear took 0.003 sec FAILED Expected exception: java.lang.IllegalArgumentException 515

Java Power Tools junit.framework.AssertionFailedError: Expected exception: java.lang.IllegalArgumentException Section 10.6. Using Parameterized Tests Unit tests are dull things to write, and developers are prone to take shortcuts. However, there is no escaping that good unit tests need to test business functions with a wide range of different data, be it boundary cases, data classes, or whatever. The same test may well succeed with one set of data, but fail with another. But if a developer needs to write a separate test case for each value (which testing best practices would suggest), he will typically not test very many values. Wouldn't it be nice to be able to run the same unit test several times, using different data? In fact, JUnit 4 does provide a neat feature that makes it easy to test using arbitrary sets of data. Basically, you can set up a collection of test data and feed it automatically into your unit test methods. Let's look at an example. Suppose that you need to write a class that calculates income tax for a given income in a certain year. The business class interface might look like this: public interface TaxCalculator { public double calculateIncomeTax(int year, double taxableIncome); } Now working out income tax typically involves some pretty nontrivial calculations. Most countries use a progressive tax system of some sort, in which the tax rate increases with the taxable income, using a system of \"tax brackets.\" In addition, the exact tax brackets sometimes vary from year to year. For this sort of application, it is important to test values within each tax bracket, as well as various boundary cases. So, we will set up a collection of test data containing the income, the year, and the expected income tax, over a wide range of values. Let's see how we could do this. JUnit 4 lets us define sets of test data, which we can pass to our unit tests. In this case, we need to test various taxable incomes in the different tax brackets. In this example, we will only test against one year (2006), but, in a real-world application, we may want to test against several years. So, our test data sets will contain three values: taxable income, year, and the amount of payable income tax. To use this test data, we need to set up a parameterized test class. This is basically a test class with a constructor that takes several parameters: precisely one parameter for each value in the test data sets. So, in our case, the constructor will take three parameters: taxable income, year and payable income tax. The parameterized test class will typically also have member variables corresponding to each of these fields. The constructor initialises these fields, and the unit test methods in the class use them to execute their tests. JUnit will instantiate a new instance of your test class for each row in the test data and then execute the class's unit tests against this data. So, if you have 20 rows of test data, JUnit will 516

Java Power Tools instantiate your test class 20 times, each time running the unit tests against a different set of data. Let's see how you would code this. The full test class is listed here: Code View: @RunWith(Parameterized.class) public class TaxCalculatorTest { @Parameters public static Collection data() { return Arrays.asList(new Object[][]{ /* Income Year Tax */ { 0.00, 2006, 0.00}, { 10000.00, 2006, 1950.00}, { 20000.00, 2006, 3900.00}, { 38000.00, 2006, 7410.00}, { 38001.00, 2006, 7410.33}, { 40000.00, 2006, 8070.00}, { 60000.00, 2006, 14670.00}, {100000.00, 2006, 30270.00}, }); } private double revenue; private int year; private double expectedTax; public TaxCalculatorTest(double input, int year, double expectedTax) { this.revenue = revenue; this.year = year; this.expectedTax = expectedTax; } @Test public void calculateTax() { TaxCalculator calculator = getTaxCalculator(); double calculatedTax = calculator.calculateIncomeTax(year, revenue); assertEquals(expectedTax, calculatedTax); } private TaxCalculator getTaxCalculator() { TaxCalculator calculator = new TaxCalculatorImpl(); return calculator; } } 517

Java Power Tools Let's look at each part of this class in detail. First of all, you need to use the @RunWith annotation, specifying the Parameterized class, to let JUnit know that your test class contains parameterized test cases. @RunWith(Parameterized.class) public class TaxCalculatorTest {... Next, you need to set up a collection of test data. You do this by defining a function, tagged with the @Parameters annotation, which returns the test data in the form of a collection. Behind the scenes, the test data is usually a list of arrays. In our case, we set up a list of arrays of values, with each array containing three values: the income, the year, and the expected tax for that income in that year: @Parameters public static Collection data() { return Arrays.asList(new Object[][]{ /* Revenue Year Tax */ { 0.00, 2006, 0.00}, { 10000.00, 2006, 1950.00}, { 20000.00, 2006, 3900.00}, { 38000.00, 2006, 7410.00}, { 38001.00, 2006, 7410.33}, { 40000.00, 2006, 8070.00}, { 60000.00, 2006, 14670.00}, {100000.00, 2006, 30270.00}, }); } As we mentioned earlier, when JUnit 4 runs this class, it actually creates an instance of the class for each line in the test data collection. You need to provide member variables to store each of these values, and a public constructor to initialize them so that JUnit can set up each instance with the correct test data: Code View: private double revenue; private int year; private double expectedTax; public TaxCalculatorTest(double revenue, int year, double expectedTax) { this.revenue = revenue; this.year = year; this.expectedTax = expectedTax; } Now we just test against these values: 518

Java Power Tools @Test public void calculateTax() { TaxCalculator calculator = getTaxCalculator(); double calculatedTax = calculator.calculateIncomeTax(year, revenue); assertEquals(expectedTax, calculatedTax); } When you run these unit tests, the test will be run many times, once for each line in the data array: Testsuite: com.wakaleo.jpt.alexandria.services.TaxCalculatorTest Tests run: 8, Failures: 0, Errors: 0, Time elapsed: 0.119 sec Testcase: calculateTax[0] took 0.012 sec Testcase: calculateTax[1] took 0.001 sec Testcase: calculateTax[2] took 0.002 sec Testcase: calculateTax[3] took 0.001 sec Testcase: calculateTax[4] took 0.001 sec Testcase: calculateTax[5] took 0.001 sec Testcase: calculateTax[6] took 0.002 sec Testcase: calculateTax[7] took 0.003 sec Note that you can put many unit tests in a parameterized unit test class, just as you would in a normal unit test class. Each individual unit test method will be run against each row of test data. Section 10.7. Using assertThat and the Hamcrest Library JUnit 4.4 introduced a new notation for assert statements designed to make the intentions of the developer clearer and easier to read. This notation, originally developed by Joe Walnes, [44] uses the assertThat method, along with set of matcher statements (or constraints, or predicates, depending on your background), which can quite nicely improve the readability of your tests. For example, the following class tests that, in this situation, the calculated tax is zero: import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; public class TaxCalculatorTest { @Test public void calculateTax() { TaxCalculator calculator = getTaxCalculator(); double calculatedTax = calculator.calculateIncomeTax(2007, 0); 519

Java Power Tools assertThat(calculatedTax, is(0.0)); } } [44] http://joe.truemesh.com/blog/000511.html Now assertThat(calculatedTax, is(0.0)) is arguably more readable than assertEquals(calculatedTax, 0.0, 0.0), although this may be a matter of personal preference. For me, it certainly reads more naturally. It's probably the fraction of a second that your brain takes to convert \"assertsEquals\" into a sentence structure along the lines of \"yeah right, so calculated tax has to equal zero.\" With the first form, your brain goes \"OK, we're asserting that calculated tax is zero.\" This requires less work. More readable tests also mean more reliable and maintainable tests. If your tests are easy to read, it's easy to see that they are correct. You can use the equalTo matcher (or is, in a shorthand form) as a more readable version of the assertEquals method: String result = \"red\"; ... assertThat(result, equalTo(\"red\")); These statements can also be combined for more complex tests. For example, using the anyOf matcher statement, the following test checks that the color variable is red, green, or yellow: assertThat(color, anyOf(is(\"red\"),is(\"green\"),is(\"yellow\"))); If necessary, you can add a description of your test to make things even clearer: String color = \"noir\"; assertThat(\"black is black\", color, is(\"black\")); This will generate an error message with a bit more depth: <<< FAILURE! java.lang.AssertionError: black is black Expected: \"black\" got: \"noir\" ... You can also use the not matcher to negate any other matcher in a fairly intuitive way: String color = \"black\"; 520

Java Power Tools assertThat(color, is(not((\"white\")))); These new methods actually come from a third-party library called Hamcrest. The range of matchers that comes with JUnit 4.4 is actually relatively limited. For a more complete set, you should include the hamcrest-all.jar library in your project. You can download this API from the Hamcrest web site. If you are using Maven, you can simply include a [*] reference in your POM file, as shown here: <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.1</version> <scope>test</scope> </dependency> Then replace the static import of org.hamcrest.CoreMatchers to org.hamcrest.Matchers. This will give you access to a much richer set of matchers. Some of these additional features are discussed in the remainder of this section. [*] http://code.google.com/p/hamcrest/downloads/list Many of the more interesting matchers make it easy to work with collections. For example, the hasItem matcher can be used to search the contents of a list (hasItemInArray does the same thing for array structures): List<String> colors = new ArrayList<String>(); colors.add(\"red\"); colors.add(\"green\"); colors.add(\"yellow\"); ... assertThat(colors, hasItem(\"red\")); You can use the hasItem and hasItemInArray to build nontrivial tests about list values. Here, for example, we check that a list has no entry: List<Integer> ages = new ArrayList<Integer>(); ages.add(20); ages.add(30); ages.add(40); ... assertThat(ages, not(hasItem(lessThan(18)))); 521

Java Power Tools Conversely, the isIn matcher lets you check whether a particular object is contained in a list: assertThat(20, isIn(ages)); Collection support is not limited to lists. The hasKey and hasValue matchers can be used to check whether a Map contains a certain key or value: Map map = new HashMap(); map.put(\"color\", \"red\"); ... assertThat(map, hasValue(\"red\")); You can even use the hasProperty matcher to perform tests on the properties of an object: Client client = new Client(); client.setClientName(\"Jane\"); ... assertThat(client, hasProperty(\"clientName\", is(\"Jane\"))); This is just a sample of what you can do with this type of expression. Check out the latest API documentation to see what else is available. The bottom line is that they can give your test cases more clarity and more expressiveness, which in turn allows you to code better, more reliable tests, more quickly and more easily. Section 10.8. JUnit 4 Theories Another major new feature introduced in JUnit4.4, albeit with an experimental status, is the notion of theories. A theory expresses a general assertion that holds true across a, possibly infinite, number of data sets. Any constraints to the data sets to which the theory applies are specified as assumptions. The developer first specifies a set of data points for testing the theory. A data point is a (generally constant) piece of test data, identified by the @DataPoint annotation. Alternatively, automated tools may analyze the code and automatically create data sets to reinforce or disprove the theory. For example, here we define the years 2007 and 2008 as valid test data: @DataPoint public static int YEAR_2007 = 2007; @DataPoint public static int YEAR_2008 = 2008; Another set of data can be used to define test data used for possible revenue test data: 522

Java Power Tools @DataPoint public static double INCOME_1 = 0.0; @DataPoint public static double INCOME_2 = 0.01; @DataPoint public static double INCOME_3 = 100.0; @DataPoint public static double INCOME_4 = 13999.99; @DataPoint public static double INCOME_5 = 14000.0; To define a theory-enabled test, you use the @Theory annotation instead of the usual @Test annotation. A theory is an ordinary method that takes a certain number of parameters. JUnit will work out which data points to use for the various parameters in your test methods based on their respective types. Each data point will be passed to each parameter of the same type. This can be a little confusing if there are several parameters of the same type. As we will see, you use assumptions to limit the allowed values for each individual parameter. The next step is to define your assumptions using the @assumeThat annotation. Indeed, by placing assumptions within a theory-enabled test case, you limit the test data that will be used to execute that test case. In the following example, we limit a test case to the year of 2007, for incomes greater than $0 and less than $14,000: assumeThat(year, is(2007)); and assumeThat(income, both(greaterThan(0.00)).and(lessThan(14000.00))); The JUnitRunner runs the test with all possible combinations of the set of data points that pass the assumptions, in this case YEAR_2007 with INCOME_2, INCOME_3, and INCOME_4: Code View: import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.junit.Assume.assumeThat; import java.math.BigDecimal; import org.junit.experimental.theories.DataPoint; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; @RunWith(Theories.class) public class TaxCalculatorTheoryTest { @DataPoint public static int YEAR_2007 = 2007; @DataPoint public static int YEAR_2008 = 2008; @DataPoint public static BigDecimal INCOME_1 = new BigDecimal(0.0); 523

Java Power Tools @DataPoint public static double INCOME_2 = 0.01; @DataPoint public static double INCOME_3 = 100.0; @DataPoint public static double INCOME_4 = 13999.99; @DataPoint public static double INCOME_5 = 14000.0; @SuppressWarnings(\"unchecked\") @Theory public void lowTaxRateIsNineteenPercent(int year, double income) { assumeThat(year, is(2007)); assumeThat(income, allOf(greaterThan(0.00),lessThan(14000.00))); TaxCalculator calculator = getTaxCalculator(); double calculatedTax = calculator.calculateIncomeTax(year, income); double expectedIncome = calculatedTax * 1000/195; assertThat(expectedIncome, closeTo(income,0.001)); System.out.println(\"Year: \" + year + \", Income: \" + income + \", Tax: \" + calculatedTax); } private TaxCalculator getTaxCalculator() { return new TaxCalculatorImpl(); } } Output from this test is: Year: 2007, Income: 0.01, Tax: 0.0019500000000000001 Year: 2007, Income: 100.0, Tax: 19.5 Year: 2007, Income: 13999.99, Tax: 2729.99805 For simplicity, we are just using double values here. For a real business application, you would typically use a more precise type for the monetary values, such as BigDecimal or a dedicated Money class. On failure of a test, a descriptive message includes details of the data points that caused the failure: org.junit.experimental.theories.internal.ParameterizedAssertionError: lowTaxRateIsNineteenPercent(2007, 0.01) Caused by: java.lang.AssertionError: Expected: is <0.01> Got: is <0.0> 524

Java Power Tools You can then add other theories to test other subsets of your test data. The applicable set of DataPoints, as constrained by the assumptions, will be applied to each Theory. Section 10.9. Using JUnit 4 with Maven 2 Maven 2 uses the Surefire plug-in to execute unit tests (see Section 2.13). The Surefire plug-in handles both JUnit 3 and JUnit 4 unit tests seamlessly: the test classes just need to be in the test directory and Maven will automatically detect and run them. You can even combine JUnit 3 and JUnit 4 tests in the same application. You run your unit tests in exactly the same way as you would any other tests in Maven, that is, by using the mvn test command: $ mvn test [INFO] Scanning for projects... ... ------------------------------------------------------- T E S T S ------------------------------------------------------- ... Results : Tests run: 68, Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 4 seconds [INFO] Finished at: Tue Aug 14 22:28:51 GMT+12:00 2007 [INFO] Final Memory: 7M/67M [INFO] ------------------------------------------------------------------------ This will run both your JUnit 3 and JUnit 4 tests, and generate the usual set of Surefire reports with the combined results of all your tests. This is very useful if you wish to use JUnit 4 features for your normal unit tests, but still benefit from the many excellent JUnit-3 based test libraries such as StrutsTestCase (see Chapter 19), the Spring MVC testing framework, or DBUnit. 525

Java Power Tools Section 10.10. Using JUnit 4 with Ant JUnit 4 is poorly supported in any versions of Ant earlier than 1.7.0. From Ant 1.7.0 onward, however, JUnit 4 tests are fully supported and easy to configure. In this section, we will go through the steps of setting up, compiling, and running your JUnit 4 tests using Ant. For completeness, we will go through the whole build file. Most of it will be straightforward to developers familiar with Ant (see Chapter 1). In the first part of the build file, we just define project directories and housekeeping tasks: <project name=\"JUnit-Tests-Sample\" default=\"runtests\" basedir=\".\"> <property name=\"junit.home\" value=\"/home/john/tools/junit4.1\" /> <property name=\"java.src\" value=\"src/main/java\" /> <property name=\"test.src\" value=\"src/test/java\" /> <property name=\"build.dir\" value=\"target\" /> <property name=\"java.classes\" value=\"${build.dir}/classes\" /> <property name=\"test.classes\" value=\"${build.dir}/test-classes\" /> <property name=\"test.reports\" value=\"${build.dir}/test-reports\" /> <target name=\"init\"> <mkdir dir=\"${java.classes}\"/> <mkdir dir=\"${test.classes}\"/> <mkdir dir=\"${test.reports}\"/> </target> <target name=\"clean\"> <delete dir=\"${build.dir}\"/> </target> Then, we define a task to compile our Java code: <target name=\"compile\" depends=\"init\" > <javac srcdir=\"${java.src}\" destdir=\"${java.classes}\" > <include name=\"**/*.java\"/> </javac> </target> Again, there is nothing special here: we are just compiling Java code using the standard Ant <javac> task. The next section, however, starts getting a little more interesting. Here, we set up a classpath that refers to the JUnit 4.1 JAR file and the application's compiled Java classes, and use it to compile the JUnit 4 unit tests. JUnit 4 is backward-compatible with JUnit 3, so unit tests written using the two APIs can comfortably live together in the same project without picking fights: 526

Java Power Tools <path id=\"test.classpath\"> <pathelement location=\"${junit.home}/junit-4.1.jar\" /> <pathelement location=\"${java.classes}\" /> </path> <target name=\"compiletests\" depends=\"compile\"> <javac srcdir=\"${test.src}\" destdir=\"${test.classes}\"> <classpath refid=\"test.classpath\" /> <include name=\"**/*.java\"/> </javac> </target> Now we are ready to actually run our unit tests. Ant 1.7.0 comes with a new and improved JUnit task that supports both JUnit 3 and JUnit 4 tests. A typical JUnit test task in Ant 1.7.0 looks like this: <target name=\"runtests\" depends=\"compiletests\"> <junit printsummary=\"yes\" haltonfailure=\"yes\"> <classpath> <path refid=\"test.classpath\" /> <pathelement location=\"${test.classes}\"/> </classpath> <formatter type=\"plain\"/> <formatter type=\"xml\"/> <batchtest fork=\"yes\" todir=\"${test.reports}\"> <fileset dir=\"${test.src}\"> <include name=\"**/*Test*.java\"/> </fileset> </batchtest> </junit> </target> The first interesting item (for users of JUnit with previous versions of Ant) is the classpath entry. This is where you tell Ant where to find the JUnit 4 jar file. This is worth mentioning because, until Ant 1.6.5, you needed to place a copy of the junit.jar file in the Ant lib directory if you wanted the JUnit task to work. Although this quirk was documented in the Ant manual and officially declared \"not a bug,\" it was messy at the best of times. However, as of Ant 1.7.0, you can simply declare your JUnit 4 JAR file in the nested classpath as shown here. Next comes a list of formatter objects. Test results can be generated in several formats: plain generates simple text files, whereas xml results in more detailed test reports suitable for HTML report generation. 527

Java Power Tools The actual tests are executed by the <batchtest> element, which runs all JUnit tests found in the specified fileset. No distinction is made between JUnit 3 and JUnit 4 unit tests. When you invoke this target, you should get something like the following: $ ant runtests Buildfile: build.xml init: compile: [javac] Compiling 11 source files to /home/john/Documents/book/java-power-tools/src/sample-code/alexandria/target/class es compiletests: [javac] Compiling 4 source files to /home/john/Documents/book/java-power-tools/src/sample-code/alexandria/target/ test-classes runtests: [junit] Running com.wakaleo.jpt.alexandria.domain.CatalogTest [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 4.493 sec [junit] Running com.wakaleo.jpt.alexandria.domain.LegacyJUnit3CatalogTest [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.041 sec [junit] Running com.wakaleo.jpt.alexandria.services.PriceCalculatorTest [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.048 sec [junit] Running com.wakaleo.jpt.alexandria.services.TaxCalculatorTest [junit] Tests run: 8, Failures: 0, Errors: 0, Time elapsed: 0.054 sec BUILD SUCCESSFUL Section 10.11. Selectively Running JUnit 4 Tests in Ant The Ant JUnit task is a flexible tool, and you can use it to pick and choose which unit tests you want to run at a particular time. This section discusses various techniques you can use to do this. 10.11.1. Running Individual Tests The usual way to run your unit tests is en masse, using the <batchtest> element. However, you can run individual tests, using the <test> element: 528

Java Power Tools <target name=\"runtest\" depends=\"compiletests\"> <junit printsummary=\"yes\" haltonfailure=\"yes\"> ... <test name=\"com.wakaleo.jpt.alexandria.domain.CatalogTest\"/> </junit> </target> Invoking this target runs only the unit tests found in this class: $ ant runtest Buildfile: build.xml init: compile: compiletests: runtest: [junit] Running com.wakaleo.jpt.alexandria.domain.CatalogTest [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 9.02 sec BUILD SUCCESSFUL In this situation, you may well want to exclude this test from your main unit tests, using an <exclude> element as shown here: <target name=\"runtests\" depends=\"compiletests\"> <junit printsummary=\"yes\" haltonfailure=\"yes\"> ... <batchtest fork=\"yes\" todir=\"${test.reports}\"> <fileset dir=\"${test.src}\"> <include name=\"**/*Test*.java\"/> <exclude name=\"**/CatalogTest.java\"/> </fileset> </batchtest> </junit> </target> 10.11.2. Running Tests Conditionally In some cases, you may prefer not to run all of your test classes each time you run your normal unit tests. Some types of tests—such as load tests, integration tests and performance tests—can be time-consuming, and need not be run each time you recompile your application. Developer unit tests should be kept short and snappy, and the slower, more processor-intensive tests should only be run when needed. The latter tests are 529

Java Power Tools typically run only on request on the developer's machines but systematically on the integration server. One way to do this is to use the if attribute of the <batchtest> element. This attribute specifies a property that must be set for the unit tests to run; otherwise, they are simply skipped. The following target will be run only if the perftests property is set: <target name=\"runperftests\" depends=\"compiletests\"> <junit printsummary=\"yes\" haltonfailure=\"yes\"> ... <batchtest fork=\"yes\" todir=\"${test.reports}\" if=\"perftests\"> <fileset dir=\"${test.src}\"> <include name=\"**/*PerfTest*.java\"/> </fileset> </batchtest> </junit> </target> The performance tests will never be run unless this property is set, even if the target is called by name: $ ant runperftests Buildfile: build.xml init: compile: compiletests: runperftests: BUILD SUCCESSFUL Total time: 1 second However, if you set the perftests property (to any value: it doesn't matter), the performance tests will be correctly executed. You can set properties in a number of ways: explicitly in the build file, in a properties file that is loaded into the build script using the <property> task, or simply from the command line: $ ant runperftests -Dperftests=true Buildfile: build.xml init: compile: 530

Java Power Tools compiletests: runperftests: [junit] Running com.wakaleo.jpt.alexandria.domain.CatalogPerfTest [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 7.227 sec [junit] Running com.wakaleo.jpt.alexandria.services.PriceCalculatorPerfTest [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.192 sec BUILD SUCCESSFUL One typically uses this command-line property uniquely on the integration server: performance and integration tests will only be run here, and not repeatedly on every developer's machine. If you use this technique, don't forget to exclude these tests from the main unit test run using the <exclude> element discussed above. Section 10.12. Integration Tests Unit tests should be short and snappy, and give a quick turnaround time. Unit tests shouldn't use external resources such as databases or web application frameworks. To do this, you often use interfaces, mock objects, and a variety of other techniques to ensure that you are testing each component in isolation. However, you will need to see how the components fit together at some point. This point is called the \"integration tests\" phase. Here, you might test your Hibernate-based DAOs against a real database (as opposed to an embedded one), run queries that go all the way from the service layer to the database and back, or simulate a user's web browser using a tool like Selenium. You might also want to see how the application holds up under load, or with many simultaneous requests. These tests are vitally important, but they would slow things down far too much if they had to be run every time a developer runs through the ordinary unit tests. Slow unit tests discourage developers from testing, so you need a way to distinguish fast unit tests from the slower integration tests. In Maven, you can configure the Surefire plug-in to determine what tests are run during the unit tests phase (when you run mvn test), and which ones are run during the integration tests (when you run mvn integration-test). In the following example, integration tests have names that end in \"IntegrationTest.\" This is a simple, arbitrary convention: you can, of course, define your own. The following configuration excludes the integration tests from the ordinary unit tests (associated with the \"test\" phase), and attaches them to the \"integration-test\" phase instead: Code View: <project> 531

Java Power Tools ... <build> <plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> <executions> <execution> <id>unit-tests</id> <phase>test</phase> <goals> <goal>test</goal> </goals> <configuration> <excludes> <exclude>**/*IntegrationTest.java</exclude> </excludes> </configuration> </execution> <execution> <id>integration-tests</id> <phase>integration-test</phase> <goals> <goal>test</goal> </goals> <configuration> <includes> <include>**/*IntegrationTest.java</include> </includes> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project> Then, to run your performance tests, just invoke the integration test phase: $ mvn integration-test 532

Java Power Tools Section 10.13. Using JUnit 4 in Eclipse Working from within your IDE is probably the easiest and most productive way to run your unit tests. JUnit 4 integrates extremely smoothly with Eclipse: you run JUnit 4 tests in exactly the same way as for JUnit 3 tests, by using \"Run As...JUnit Test.\" If you are using Java 5-style asserts, you will also need to place the -ea (\"enable assertions\") option in the Run configuration screen (see Figure 10-1). Otherwise, your asserts will simply be ignored. Figure 10-1. Configuring JUnit 4 test runs to use assert operations Eclipse even handles JUnit 4-specific features such parameterized tests correctly (see Figure 10-2). Figure 10-2. Running JUnit4 tests in Eclipse 533

Java Power Tools You can also create new JUnit4 test cases easily in Eclipse by selecting \"New...JUnit Unit Test\" (see Figure 10-3). This dialog box lets you create either JUnit 3.8 or JUnit 4 test classes (you can uses both types of unit tests simultaneously in the same project). Figure 10-3. Creating a new JUnit4 test in Eclipse 534

Java Power Tools Chapter 11. Next-Generation Testing with TestNG Introducing TestNG Creating Simple Unit Tests with TestNG Defining TestNG Test Suites The TestNG Eclipse Plug-In Using TestNG in Ant Using TestNG with Maven 2 Managing the Test Lifecycle Using Test Groups Managing Dependencies Parallel Testing 535

Java Power Tools Test Parameters and Data-Driven Testing Checking for Exceptions Handling Partial Failures Rerunning Failed Tests 11.1. Introducing TestNG TestNG is an innovative unit test framework, written by Cédric Beust and Alexandru Popescu, designed to overcome many of the perceived shortcomings of JUnit 3 (see Section 10.1). Like JUnit 4, TestNG improves on JUnit 3 in many ways, removing syntactical constraints and adding flexible, nonintrusive annotation-based testing. In addition, TestNG also supports many powerful features such as test groups, dependencies, and parallel testing—features that are not yet supported by JUnit 4 at the time of this writing. TestNG integrates well with IDEs such as Eclipse and build tools like Ant and Maven. All of these features make it easier to write better-designed, faster and more flexible unit tests. Section 11.1. Introducing TestNG Creating Simple Unit Tests with TestNG Defining TestNG Test Suites The TestNG Eclipse Plug-In Using TestNG in Ant Using TestNG with Maven 2 Managing the Test Lifecycle Using Test Groups Managing Dependencies Parallel Testing Test Parameters and Data-Driven Testing Checking for Exceptions Handling Partial Failures Rerunning Failed Tests 536

Java Power Tools 11.1. Introducing TestNG TestNG is an innovative unit test framework, written by Cédric Beust and Alexandru Popescu, designed to overcome many of the perceived shortcomings of JUnit 3 (see Section 10.1). Like JUnit 4, TestNG improves on JUnit 3 in many ways, removing syntactical constraints and adding flexible, nonintrusive annotation-based testing. In addition, TestNG also supports many powerful features such as test groups, dependencies, and parallel testing—features that are not yet supported by JUnit 4 at the time of this writing. TestNG integrates well with IDEs such as Eclipse and build tools like Ant and Maven. All of these features make it easier to write better-designed, faster and more flexible unit tests. Section 11.2. Creating Simple Unit Tests with TestNG Before discussing the more advanced features of TestNG, we will take a quick introductory tour. Let's look at how to get started with TestNG. TestNG classes are ordinary Java classes with ordinary methods: They don't have to extend a particular class, nor do their methods have to follow any particular naming convention. You simply use the @Test annotation to flag unit test methods, and use Java 5 asserts to test calculated values against expected ones. Throughout this chapter, we will use the example of a class that calculates GST (goods and services tax, also known as a value added tax in some countries), which we introduced in Section 10.1. This class is supposed to calculate the net price of something, taking into account the current GST rate. Suppose that the standard GST rate is 12.5 percent. Our unit test class might look like this: import org.testng.annotations.Test; public class PriceCalculatorTests { @Test public void calculateGST() { PriceCalculator calculator = new PriceCalculator(); double amountWithGst = calculator.calculateGST(100.00); assert (112.50 == amountWithGst) : \"Standard GST should be 12.5%\"; } } You may prefer the old JUnit 3 assert methods (assertEquals(), and so on). TestNG via also supports these by using static imports. This approach is also used by JUnit 4 (see Section 10.2). Code View: import org.testng.annotations.Test; 537

Java Power Tools import static org.testng.Assert.assertEquals; public class PriceCalculatorTests { @Test public void calculateGST() { PriceCalculator calculator = new PriceCalculator(); double amountWithGst = calculator.calculateGST(100.00); assertEquals(\"Standard GST should be 12.5%\", amountWithGst, 112.50 , 0.0); } } Test frameworks generally let you define code that needs to be run before every test. In JUnit 3.x, you override the setUp() and tearDown() methods. TestNG comes with a rich set of annotations for different types of fixture code (see Section 11.7). In the following example, we use the @BeforeMethod annotation to ensure that the init() method is called before each and every test case. Conversely, we use the @AfterMethod annotation to make sure the tidyUp() function is called after each test: Code View: import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; public class PriceCalculatorTests { PriceCalculator calculator = new PriceCalculator(); @BeforeMethod public void init() { calculator = new PriceCalculator(); } @Test public void calculateGST() { double amountWithGst = calculator.calculateGST(100.00); assertEquals(\"Standard GST should be 12.5%\", amountWithGst, 112.50 , 0.0); } @AfterMethod public void tidyUp() { ... } 538

Java Power Tools } There are several ways to run TestNG tests. You can run it directly from the command line, but this option is not very practical for anything other than toy examples. You can also run TestNG tests directly from within Eclipse using the TestNG plug-in (see Section 11.4). Or you can integrate them into your build environment using Ant (see Section 11.5) or Maven (see Section 11.6). When you run a set of TestNG tests, it produces a report similar to the traditional JUnit reports, although, like JUnit 4 and unlike JUnit 3.x, no distinction is made between failed assertions and exceptions. The following listing is an example of running TestNG using the Ant task: $ ant test ... test: [testng] [Parser] Running: ... [testng] PASSED: findHotelsInCity [testng] PASSED: calculateGST [testng] PASSED: calculateReducedGST [testng] PASSED: calculateStandardGST [testng] =============================================== [testng] Ant test [testng] Tests run: 1037, Failures: 0, Skips: 0 [testng] =============================================== [testng] =============================================== [testng] Ant suite [testng] Total tests run: 1037, Failures: 0, Skips: 0 [testng] = This is just a quick overview of TestNG tests, which should let you get the feel of the API. There are many other annotations and features, such as groups and dependencies, which we will investigate later on in this chapter. Section 11.3. Defining TestNG Test Suites Traditionally, TestNG unit tests are generally organized into test suites. In TestNG, a test suite is a logical set of tests that you expect to run together. You define TestNG test suites using a TestNG configuration file, an XML configuration file that tells TestNG how your tests are organized and where it needs to look for them. This is a little more complicated than a JUnit test configuration, where, if you are using Maven (see Section 11.6) or Ant (see Section 11.5), you can get away with just writing test classes and placing them in the test source code directory, without having to set up a TestNG configuration file. But it's sometimes worth the extra effort of using TestNG configuration files for the flexibility and readability it gives you. 539

Java Power Tools Here is a simple test suite configuration file. Here, we simply list the test classes we want to test: <!DOCTYPE suite SYSTEM \"http://testng.org/testng-1.0.dtd\" > <suite name=\"Suite\" verbose=\"2\" > <test name=\"Domain tests\" annotations=\"JDK\"> <classes> <class name=\"com.wakaleo.jpt.hotel.domain.PriceCalculatorTests\"/> <class name=\"com.wakaleo.jpt.hotel.domain.HotelTests\"/> <class name=\"com.wakaleo.jpt.hotel.domain.CityTest\"/> <class name=\"com.wakaleo.jpt.hotel.domain.CountryTest\"/> </classes> </test> </suite> TestNG supports both Java 5 annotations and the older Javadoc-style annotations for JDK 1-4. The annotations=\"JDK\" attribute in the previous listing indicates that we are working with Java 5 annotations, which is what we will use throughout the rest of this chapter. You can also specify a list of packages rather than a list of classes, which will run all the tests contained in the specified package: <suite name=\"Suite\" verbose=\"2\" > <test name=\"Domain tests\" annotations=\"JDK\"> <packages> <package name=\"com.wakaleo.jpt.hotel.domain\" /> </packages> </test> </suite> To make things even simpler, you can use wildcard characters in package and class names. The following test suite includes any classes in any packages directly or indirectly contained in the com.wakaleo.jpt package: <suite name=\"Suite\" verbose=\"2\" > <test name=\"Application tests\" annotations=\"JDK\"> <packages> <package name=\"com.wakaleo.jpt.*\" /> </packages> </test> </suite> 540

Java Power Tools Using configuration files in TestNG is not obligatory. In many cases, it is more convenient to run TestNG against a set of classes, using test groups if necessary to decide which tests should or should not be executed (see Section 11.8), which you can do fairly easily in Ant or directly from Eclipse (see Section 11.4). However, configuration files are sometimes useful to organize your tests in a clear and readable manner. Section 11.4. The TestNG Eclipse Plug-In One of the most effective ways to run unit tests is from within an IDE such as Eclipse or NetBeans. This approach allows a more seamless development process and a tighter testing cycle. At the time of this writing, TestNG plug-ins exist for Eclipse and IntelliJ. In this section, we will look at how to install and use the Eclipse TestNG plug-in. This excellent piece of software provides invaluable tools for writing, maintaining, and running your TestNG test cases from within Eclipse. 11.4.1. Installing the TestNG Plug-In You install the TestNG plug-in from the Remote Update site in the usual way: 1. Open the \"Install/Update\" window (Help Software updates Find and Install) and select \"Search for new features to install.\" 2. Create a \"New Remote Site.\" 3. Enter http://beust.com/eclipse for the URL and \"TestNG Plugin\" (or some other appropriate name) for the name. 4. Make sure the \"TestNG Plugin\" checkbox is checked in the site list, and click \"Finish.\" 5. In the next window, check the \"TestNG\" box in the features to install, and step through the installation process. Once you have finished, you may need to restart Eclipse. You can verify the installation by opening the TestNG view (Windows Show View Other…), as shown in Figure 11-1. This will open the TestNG dashboard at the bottom of the screen. Figure 11-1. Opening the TestNG view in Eclipse 541

Java Power Tools 11.4.2. Running TestNG Tests Running a TestNG test class, or an individual TestNG-annotated unit test in Eclipse is intuitive and easy, and very similar to what you would do for a JUnit test case: just select the class or method in the Outline view and select \"Run As TestNG Test\" in the contextual menu (see Figure 11-2). This will run the corresponding tests and display the results in the Console view and in the TestNG results view (see Figure 11-3). If you want to step through the code using the IDE debugging perspective, select \"Debug As TestNG Test\" instead. Figure 11-2. Running TestNG tests in Eclipse 542

Java Power Tools Running multiple tests is a bit more involved. One way is to use a test suite (see Section 11.3). First of all, you need a TestNG configuration file which defines the tests you want to run. Then, just select the configuration file in the Outline view, and select \"Run As TestNG Suite\" in the contextual menu. This will run all of the tests defined in this test suite. When you execute TestNG tests in Eclipse, either by running the tests in an individual class or by executing the tests defined in a test suite, TestNG will display the test results in the TestNG view at the bottom of the screen (see Figure 11-3). Figure 11-3. TestNG test results in Eclipse Another way to run multiple tests is to use TestNG run configurations. You can set up run configurations to also configure TestNG in Eclipse to run a particular group (or groups) of tests. Test groups (see Section 11.8) are a particularly useful way of organizing your unit tests into meaningful subsets, which can be run at different times or under different circumstances. To run all of the tests in a group, you need to set up a new Test Configuration. Open the Configuration Management window ( \"Run As Run\") and create a new TestNG configuration (see Figure 11-4). From here, you can set up a configuration to run a particular unit test class, group or groups, or test suite. The Browse buttons make it easy to select the various test objects. Browsing for classes will list all known TestNG classes (that is, all classes containing TestNG-annotated test methods). Browsing the groups lets you select from the known test groups defined within the project (see Figure 11-5). And browsing for Suites will list all the known test suite configuration files within the current projects. Figure 11-4. Setting up a TestNG Run Configuration 543

Java Power Tools Figure 11-5. Selecting groups in a TestNG Run Configuration Run configurations are a useful and reasonably flexible way to identify a given set of tests that you need to run repeatedly. This can be useful to separate quick-running unit tests from heavier integration tests, or to factor out performance tests, for example. Once you have finished setting up your run configuration, you can easily come back and run (or debug) it again at any time. 544

Java Power Tools Section 11.5. Using TestNG in Ant In a professional development environment, it is important to be able to run your tests in a reproducible and predictable manner. The best way to do this is to integrate your tests into your build process, whether it be using Ant, Maven, or some other build tool. TestNG works neatly with both Ant and Maven. Here we will look at how to use TestNG in Ant. TestNG comes bundled with a convenient Ant task that lets you run TestNG tests, groups of tests, or test suites, in a very flexible manner. In the rest of this section, we will go through a practical example of what you can do with this task. You define the TestNG task in a fairly standard manner, using the Ant <taskdef> task and indicating the location of the TestNG JAR file. In this example, I installed TestNG 5.3 in the /usr/local/testng directory, and we are interested in the JDK 1.5 version of TestNG. So we could set up the Ant <taskdef> as follows: Code View: <!-- TestNG resources --> <property name=\"testng.home\" value=\"/usr/local/testng\" /> <property name=\"jdk15.testng.jar\" value=\"${testng.home}/testng-5.5-jdk15.jar\" /> <taskdef resource=\"testngtasks\" classpath=\"${jdk15.testng.jar}\"/> The <taskdef> instruction defines the <testng> task, which you can use to run your unit tests in a number of ways. First, however, you need to compile your classes and test classes in the usual way. In a real-world Ant project, the way you would do this can vary quite a bit, particularly with regards to directory structures. For completeness, an example of these tasks is shown here. The directory structure is represented by Ant properties: java.src is the root directory containing the application source code; test.src is the root directory containing the unit test source code; java.classes and test.classes contain the compiled application classes and unit tests, respectively: Code View: <target name=\"init\" description=\"Create required work directories\"> <mkdir dir=\"${java.classes}\"/> <mkdir dir=\"${test.classes}\"/> <mkdir dir=\"${test.reports}\"/> </target> <target name=\"compile\" depends=\"init\" description=\"Compile application classes\"> 545

Java Power Tools <javac srcdir=\"${java.src}\" destdir=\"${java.classes}\" includes=\"**/*.java\" /> </target> <path id=\"tests.classpath\"> <pathelement location=\"${jdk15.testng.jar}\" /> <pathelement location=\"${java.classes}\" /> </path> <target name=\"compiletests\" depends=\"compile\" description=\"Compile test classes\"> <javac srcdir=\"${test.src}\" destdir=\"${test.classes}\" classpathref=\"tests.classpath\" includes=\"**/*.java\" /> </target> <path id=\"runtests.classpath\"> <path refid=\"tests.classpath\"/> <pathelement location=\"${test.classes}\" /> </path> This last classpath (runtests.classpath) is the one that we are going to use with the TestNG task. It contains, logically enough, all of the compiled application classes, test classes, dependencies, and the TestNG JAR file. Now we are ready to run our TestNG unit tests. The TestNG Ant task is flexible, and you can use it in many ways. The easiest way to get started is simply to run TestNG against a set of Java files. This is very easy to set up: all you need to define is the classpath that we set up earlier, and an output directory in which the test result reports will be generated (defined here by the test.reports property). Lots of other options are available: we also set the verbose attribute to see more details on the console, and we set the haltonfailure attribute to \"true\" to force the build to halt if there is a unit test failure: Code View: <target name=\"runtests\" depends=\"compiletests\" description=\"Run TestNG unit tests\"> <testng classpathref=\"runtests.classpath\" outputDir=\"${test.reports}\" verbose=\"2\" haltonfailure=\"true\"> <classfileset dir=\"${test.classes}\" includes=\"**/*.class\" /> </testng> </target> 546

Java Power Tools Note that here you don't need to define a TestNG configuration file: TestNG will figure out which classes contain unit tests by itself just fine. Let's take it for a spin: $ ant runtests Buildfile: build.xml ... runtests: [testng] [Parser] Running: [testng] Ant suite [testng] PASSED: findCityByCode [testng] PASSED: loadCity [testng] PASSED: saveCity [testng] PASSED: findCityByName [testng] PASSED: findCountryByCode [testng] PASSED: loadCountry [testng] PASSED: loadHotel ... [testng] java.lang.AssertionError [testng] at com.wakaleo.jpt.hotel.domain.CountryTest.findCountryByName... [testng] ... Removed 21 stack frames [testng] FAILED: saveCountry [testng] java.lang.AssertionError [testng] at com.wakaleo.jpt.hotel.domain.CountryTest.saveCountry... [testng] ... Removed 21 stack frames [testng] =============================================== [testng] Ant test [testng] Tests run: 22, Failures: 2, Skips: 0 [testng] =============================================== [testng] =============================================== [testng] Ant suite [testng] Total tests run: 22, Failures: 2, Skips: 0 [testng] =============================================== BUILD SUCCESSFUL Total time: 1 second This task runs every TestNG-compatible unit test in the test class directory, and sends JUnit-style output to the console. It also generates HTML reports that can be sent by email or displayed on a project web site (see Figure 11-6). Although not particularly pretty, 547

Java Power Tools these reports are pragmatic and to the point. For example, any failed tests are listed at the top, because presumably that's what the developer will be looking for first. Figure 11-6. A TestNG report generated by the TestNG Ant plugin If you prefer to use a TestNG configuration file (or even several!), you can do that, too. Just use the <xmlfileset> nested element to tell TestNG which configuration files you want to use, as shown here: Code View: <target name=\"runtests\" depends=\"compiletests\" description=\"Run TestNG unit tests\"> <testng classpathref=\"runtests.classpath\" outputDir=\"${test.reports}\" verbose=\"2\" haltonfailure=\"true\"> <xmlfileset dir=\"src/test/resources\" includes=\"testng.xml\"/> </testng> </target> 548

Java Power Tools The TestNG task is very flexible and you can choose which tests to run in a variety of ways. For example, you can also run all the TestNG tests in a particular group or set of groups (see Section 11.8), and/or exclude a group or set of groups, by using the groups or excludedgroups parameters: Code View: <target name=\"unit-tests\" depends=\"compiletests\"> <testng classpathref=\"runtests.classpath\" outputDir=\"${test.reports}\" verbose=\"2\" haltonfailure=\"true\" groups=\"unit\"> <classfileset dir=\"${test.classes}\" includes=\"**/*.class\" /> </testng> </target> Or you can run a set of tests simultaneously on several threads using the parallel parameter (see Section 11.10), in order to test thread-safety or simulate load. Methods will be executed in parallel on separate threads (except tests with dependencies between them, which will be run in the same thread). For example, the following task will run the unit tests of the group \"web\" in separate, parallel threads: Code View: <target name=\"loadtests\" depends=\"compiletests\" description=\"Run TestNG unit tests\"> <testng classpathref=\"runtests.classpath\" outputDir=\"${test.reports}\" verbose=\"2\" haltonfailure=\"true\" parallel=\"methods\" groups=\"web\"> <classfileset dir=\"${test.classes}\" includes=\"**/*.class\" /> </testng> </target> Section 11.6. Using TestNG with Maven 2 Maven (or, more precisely, Surefire) recognizes TestNG test cases. In other words, Maven should pick up TestNG tests in exactly the same way as JUnit 3 and JUnit 4 tests. TestNG dependencies in Maven are a little quirky. There are actually two distributions of each version of TestNG: one compiled for JDK 1.5, and one compiled for JDK 1.4. The APIs are quite different: the first uses Java 5 annotations, whereas the second uses the old javadoc-style annotations. 549


Like this book? You can publish your book online for free in a few minutes!
Create your own flipbook