Presentation is loading. Please wait.

Presentation is loading. Please wait.

Programmer Testing Testing all things Java using JUnit and extensions.

Similar presentations


Presentation on theme: "Programmer Testing Testing all things Java using JUnit and extensions."— Presentation transcript:

1 Programmer Testing Testing all things Java using JUnit and extensions

2 The Big Why “If you don’t have tests, how do you know your code is doing the thing right and doing the right thing ?”

3 What are “Programmer Tests”? Programmer Testing is the testing performed by a developer with the goal of verifying the correct functioning of her code Programmer Tests are automated unit tests that exercise program units such as classes and methods, not the complete features or requirements supported by the software as a whole Important distinction: if it’s not automated, it’s not really programmer testing – that’s exploratory testing.

4 Safety Net Having a good test coverage with an automated unit test harness… –prevents a system from becoming legacy(*), and –enables effective refactoring, because it also –prevents regression Metaphor: Mold * Michael Feathers defines “legacy code” as code without tests

5 Available tools for Java JUnit –The de facto Java unit testing framework –Extremely simple –Plenty of extensions for J2EE, for example TestNG –Very close to JUnit but not quite –Employs @metadata instead of naming conventions

6 JUnit What is the difference between a framework and a library? Is JUnit (www.junit.org) a framework or a library?

7 JUnit 101 Essential concepts: –Test suite: Java class that extends junit.framework.TestSuite or implements a static method named suite(), returning a TestSuite –Test case: Java class extending junit.framework.TestCase –Test fixture: the initial state of a Test Case, consisting of the member variables initialized through a method named setUp() –Test method: a method of a TestCase class of which signature looks like “public void testFoo()”, representing a single logical test

8 TestCase lifecycle setUp() gets called once before each test method is executed tearDown() gets called once after each test method has been executed – regardless of whether the test passed or failed (or threw some other exception). Each testSomething() method gets called exactly once – in an arbitrary order! The same instance of a TestCase may or may not be used for executing the tests – don’t depend on the constructor, use setUp() for setup!

9 Java 1.5 annotations JUnit 3.8 Java 1.4 public void setUp() {... } public void testSomething() {... } public void tearDown() {... } JUnit 4.1 Java 1.5 @Before someSetUp() {... } @Test public void something() {... } @After public void someTearDown () {... }

10 What else is new in JUnit 4.1? Parametrized tests - same testcase is repeated for various argument sets. Annotated way to write test suites and to filter out testcases which (not) to execute

11 JUnit 101: Simple TestCase (1) import junit.framework.*; public class TestCalculator extends TestCase { protected void setUp() { super.setUp(); } protected void tearDown() { super.tearDown(); }

12 JUnit 101: Simple TestCase (2) import junit.framework.*; public class TestCalculator extends TestCase { private Calculator calculator; protected void setUp() { super.setUp(); calculator = new Calculator(); }

13 JUnit 101: Simple TestCase (3) import junit.framework.*; public class TestCalculator extends TestCase { private Calculator calculator; public void testAddingPositiveIntegers() { int expected = 5; int actual = calculator.add(2, 3); assertEquals(“2 + 3 should be 5”, expected, actual); }

14 JUnit 101: Simple TestCase (4) import junit.framework.*; public class TestCalculator extends TestCase { private Calculator calculator; protected void setUp() { … } protected void tearDown() { … } public void testAddingPositiveIntegers() { … } public void testAddingNegativeIntegers() { … } public void testAddingZeroes() { … } public void testAddingPositiveToNegative() { … } }

15 JUnit 101: Simple TestSuite (1) import junit.framework.*; public class CalculatorTestSuite extends TestCase { public static Test suite() { TestSuite suite = new TestSuite(); suite.addTest(CalculatorIntegerTest.class); suite.addTest(CalculatorFloatingPointTest.class); suite.addTest(CalculatorLogarithmsTest.class); return suite; }

16 What if I need to do something expensive in setUp()? If you need to perform some kind of preparations before running the test methods of a TestCase (and can’t/won’t replace the expensive stuff with a mock implementation), you need to wrap your TestCase with a junit.extensions.TestSetup decorator class.

17 Wrapping TestCase into TestSetup public class InterestCalculatorTestWithTestSetup extends TestCase { private static double interestRate, loanAmount; private static int loanDuration; public static Test suite() { TestSuite suite = new TestSuite(InterestCalculatorTestWithTestSetup.class); TestSetup wrapper = new TestSetup(suite) { public void setUp() throws IOException { ResourceBundle bundle = ResourceBundler.getBundle( InterestCalculatorTestWithTestSetup.class.getName()); inrerestRate = Double.parseDouble(bundle.getString(“interest.rate”)); loanAmount = Double.parseDouble(bundle.getString(“loan.amount”)); loanDuration = Interest.parseInt(bundle.getString(“loan.duration”)); } }; return wrapper; } public void testInterestCalculation() { … } }

18 Assertions We already saw one assertion in action, the assertEquals() method There are a bunch others – take a look at the Javadocs for junit.framework.TestCase at http://www.junit.org/junit/javadoc/3.8.1/ http://www.junit.org/junit/javadoc/3.8.1/ The most often used assertions – assertEquals(), assertEquals(), assertNull(), assertSame() and their opposites – are enough for most situations and the rest you can easily write on your own.

19 What happens when an assertion fails? The assertions throw a junit.framework.AssertionFailedError when they fail. JUnit’s TestRunner catches these (runtime)exceptions and tags the test as “failure” for later reference. If a test throws any other exception (e.g. NullPointerException), JUnit again catches these but tags the test as “error” instead of “failure”.

20 Mock Objects At some point, you will face a problem where the class/method you should be testing needs to collaborate with an object that is either difficult to create/obtain or simply sooo slooow that your test takes forever to execute (even a 100ms adds up when you’ve got thousands of tests…). The solution for this kind of problems is often to use a mock object.

21 What are Mock Objects? A mock object is an object that claims to implement an interface but doesn’t really. There are variations on what the “doesn’t really” part actually means (these variations are called “fake”, “stub” and “mock”) but for now, we’ll just call them all mock objects. Since there’s nothing like a good example…

22 Example: Mock Objects public class Item { public float getPriceAfterDiscounts(PricingService ps, DiscountService ds) { float basePrice = ps.getPriceFor(this); float discountedPrice = ds.applyDiscounts(this, basePrice); return discountedPrice; } public interface PricingService { float getPriceFor(Item item); } public interface DiscountService { float applyDiscounts(Item item, float basePrice); }

23 How to test that without the real PricingService & DiscountService? public class TestItemUsingMockObjects extends TestCase { private Item item; private PricingService pricingService; private DiscountService discountService; protected void setUp() { item = new Item(); pricingService = new PricingService() { public float getPriceFor(Item item) { return 12.34f; } }; discountService = new DiscountService() { public float applyDiscounts(Item item, float basePrice) { … } }; } public void testCalculateDiscountsOnBasePrice() { assertEquals(10.95f, item.getPriceAfterDiscounts(pricingService, discountService); }

24 Static vs. Dynamic Mocks That example used “static” mock objects – the other school of mock objects is “dynamic” mock objects Static mock objects fake their own behavior while dynamic mock objects also verify that the class under test collaborated with the mock objects as expected Let’s see an example to illustrate this behavior-oriented approach to using mock objects (we’ll use the EasyMock framework but there are some alternatives)

25 Using EasyMock and dynamic mock objects public class TestItemUsingMockObjects extends TestCase { private Item item; private MockControl pricingControl, discountControl; private PricingService pricingService; private DiscountService discountService; protected void setUp() { item = new Item(); pricingControl = MockControl.createControl(PricingService.class); // obtain a “remote control” pricingService = (PricingService) pricingControl.getMock(); // let EasyMock create the mock object pricingService.getPriceFor(item); // specify expected method call to our mock PricingService pricingControl.setReturnValue(12.34f); // fake the behavior by setting return value pricingControl.replay(); // switch from recording mode to replay mode // similar setup for DiscountService... } public void testCalculateDiscountsOnBasePrice() { assertEquals(10.95f, item.getPriceAfterDiscounts(pricingService, discountService); pricingControl.verify(); // verify expected interactions actually happened discountControl.verify(); // verify expected interactions actually happened }


Download ppt "Programmer Testing Testing all things Java using JUnit and extensions."

Similar presentations


Ads by Google