Chapter 11, Testing: Testing Patterns Note to Instructor: The material in this slide set is not contained in the 3rd edition of the text book. It is planned for the 4th edition.
Recall: The System Model for the Simple Inventory System
Java Code for the Simple Inventory System public class InventorySystem { private static String TALISKER = "Talisker"; private int totalStock; private Warehouse warehouse = new WarehouseImpl(); public void addToWarehouse(String item, int amount) { warehouse.add(item, amount); totalStock += amount; } public int getTotalStock() { return totalStock; public boolean processOrder(Order order) { order.fill(warehouse); return order.isFilled(); public static void main(String[] args) { InventorySystem inventorySystem = new InventorySystem(); inventorySystem.addToWarehouse(TALISKER, 50); boolean order1success = inventorySystem.processOrder(new OrderImpl(TALISKER, 50)); boolean order2success = inventorySystem.processOrder(new OrderImpl(TALISKER, 51)); System.out.println("Order1 succeeded? " + order1success + " - Order2 succeeded? " + order2success); Note in this example the UML Client method useInventorySystem() is realized as the main() method in the class InventorySystem ?
Java Code for the Warehouse public interface Warehouse { public boolean hasInventory(String item, int amount); public int getInventory(String item); public void add(String item, int amount); public void remove(String item, int amount); } public class WarehouseImpl implements Warehouse { private Map<String, Integer> inventory = new HashMap<String, Integer>(); public boolean hasInventory(String item, int amount) { return inventory.get(item) >= amount; public int getInventory(String item) { return inventory.get(item); public void add(String item, int amount) { inventory.put(item, amount); public void remove(String item, int amount) { inventory.put(item, inventory.get(item) - amount);
Java Code for the Order public interface Order { public boolean isFilled(); public void fill(Warehouse warehouse); } public class OrderImpl implements Order { private String item; private int amount; private boolean filled = false; public OrderImpl(String item, int amount) { this.item = item; this.amount = amount; public boolean isFilled() { return filled; public void fill(Warehouse warehouse) { if(warehouse.hasInventory(item, amount)) { warehouse.remove(item, amount); filled = true;
Test Model of the InventorySystem Assume we now want to unit test the class Order, our SUT Note: Order is not unit testable in isolation, it depends on Warehouse
Unit testing Order with jUnit public class OrderStateTester { private static String TALISKER = "Talisker"; private Warehouse warehouse; @Before public void setUp() { warehouse = new WarehouseImpl(); warehouse.add(TALISKER, 50); } @Test public void orderIsFilledIfEnoughInWarehouse() { Order order = new Order(TALISKER, 50); order.fill(warehouse); assertTrue(order.isFilled()); assertEquals(0, warehouse.getInventory(TALISKER)); @Test public void orderDoesNotRemoveIfNotEnough() { Order order = new Order(TALISKER, 51); assertFalse(order.isFilled()); assertEquals(50, warehouse.getInventory(TALISKER)); Needed for unit testing Order: Instantiation of WarehouseImpl +
From State Testing to Behavior Testing Observation: jUnit helps us to test the state of a SUT What if we not only want to test the state of a SUT, but also its interaction with its collaborators, for example the interaction between Order and Warehouse? Limitation of JUnit: jUnit does not provide mechanisms to test a specific sequence of operations, that is, which operations are called on collaborators and in which order Here Mock Objects come into play.
Outline of the Lecture Unit testing with jUnit (Example) Mock object pattern (Example) Dependency injection pattern (not only a testing pattern) 4 stage testing pattern Inner class test pattern Reflection test pattern Test exception pattern Test model as a new abstraction on the same level as the system model Dependency injection pattern (not only a testing pattern, good for your system health )
Recall: Subclasses of Test Doubles There are 4 types of test doubles. All doubles try to make the SUT believe it is talking to its real collaborators: Dummy object: Passed around but never actually used. Dummy objects are usually used to fill parameter lists Fake object: A fake object is a working implementation, but usually contains some type of “shortcut” which makes it not suitable for production code (Example: A database stored in memory instead of a real database) Stub: Provides canned answers to calls made during the test, but it is not able to respond to anything outside what it is programmed for Mock object: Mocks are able to mimic the behavior of the real object. They know how to deal with sequence of calls they are expected to receive.
Mock-Object Pattern Mock object In the mock object pattern a mock object replaces the behavior of a real object called the collaborator and returns hard-coded values A mock object can be created at startup- time with a factory pattern Mock objects can be used for testing state of individual objects as well as the interaction between objects, that is, to validate that the interactions of the SUT with its collaborators behave is as expected The selection of the Collaborator or Mock Collaborator is called binding (cf. Lecture 2) Mock object http://robkuijt.nl/testdesignpatterns/show.php?zk=unit-test-simulation-patterns.txt#Mock-Object-Pattern
Implementing Mock Objects Create an instance of the mock object and bind it to the abstract class or interface Set the state in the mock object Set any parameters or attributes that could be used by the object to test Set expectations in the mock object Here the desired or expected outcome is specified. This includes the number of method calls and the return values of mock object invocations Invoke SUT code with mock object(s) as parameter(s) Now that all of the expectations have been set, use the mock object in the SUT Validate consistency in the Mock Object Implement a “verify” method, which should be the final step in the test to validate that the expected outcome matches the observed outcome Note we prefer the term validation instead of verification. Source: Brown & Tapolcsanyi: Mock Object Patterns. In Proceedings of the 10th Conference on Pattern Languages of Programs, 2003. http://hillside.net/plop/plop2003/papers.html
Frameworks that implement Mock Objects jMock EasyMock MockPP GoogleMock Test::MockObject RSpec See a more comprehensive list of implementations at http://www.mockobjects.com/ In the following examples, we use EasyMock. Java C++ Perl Ruby
The EasyMock Framework The goal of the EasyMock framework is to make it easy to deal with mock objects EasyMock operates using static method imports (org.easymock.EasyMock.*) It uses a record/replay metaphor Necessary steps in using the EasyMock framework: Create the mock object for the interface of the collaborator (createMock(Class interface)) Set its state and/or record expected behavior (expect(T methodCall).andReturn(T returnValue)) Switch mock object to replay state (“ready to play”) (replay(mock)) and invoke SUT code Validate behavior (verify(mock)) For more information on EasyMock see: http://easymock.org/
Test Model of the InventorySystem with a Mock Object warehouseMock supplied by EasyMock
Testcase using the Mock Object Pattern Unit test fillingRemovesInventoryIfInStock: Check that the warehouse has bottles in its inventory Withdraw the 50 bottles Make sure the order is filled Flow of events specifying the expected behavior:
Unit Test: fillingRemovesInventoryIfInStock public class OrderInteractionTesterEasyMock { private static String TALISKER = "Talisker"; private Warehouse warehouseMock; @Test public void fillingRemovesInventoryIfInStock() { Order order = new OrderImpl(TALISKER, 50); warehouseMock = createMock(Warehouse.class); expect(warehouseMock .hasInventory(TALISKER, 50)).andReturn(true); warehouseMock.remove(TALISKER, 50); replay(warehouseMock); order.fill(warehouseMock); assertTrue(order.isFilled()); verify(warehouseMock); } 1. Create mock object 2. Specify expected behavior (“behavioral oracle”) 3. Set mock object to be ready to play 4. Validate observed behavior against expected behavior
Mock Objects Summary Mock objects are test doubles that are able to mimic the behavior of the real object The mock object pattern enables us to test state and behavior Mock objects are a way to create “self-contained” unit tests (i.e. without much interaction with the rest of the objects in the system model) Frameworks for mock objects are available in major programming languages (Java, C++, Perl, Ruby,…). In order to properly use mock objects, two patterns must be used: A factory pattern must be used to instantiate the service connection An abstract base class must be used so that all interactions with the service can be managed using virtual methods Alternatively, Aspect Oriented Programming practices can be used to establish a pointcut, but AOP is not available in many languages
Where are we now? Unit testing with jUnit (Example) Mock object pattern (Example) Dependency injection pattern (not only a testing pattern) 4 stage testing pattern Inner class test pattern Reflection test pattern Test exception pattern Test model as a new abstraction on the same level as the system model Dependency injection pattern (not only a testing pattern, good for your system health )
Problem: Unit testing the InventorySystem Recall the InventorySystem public class InventorySystem { private static String TALISKER = "Talisker“; private int totalStock; private Warehouse warehouse = new WarehouseImpl(); … } Since the InventorySystem explicitly calls new to instantiate a specific implementation of Warehouse, we cannot test this InventorySystem implementation with a mock Warehouse Can the InventorySystem implementation be changed to work with both, a production implementation of Warehouse and a mock Warehouse? ➞ Dependency Injection
Instantiation with new What is wrong with the usual way of instantiating objects with new?
Instantiation with new What is wrong with the usual way of instantiating objects with new? new creates a direct compile time dependency on the implementation !
Instantiation with new What is wrong with the usual way of instantiating objects with new? new creates a direct compile time dependency on the implementation Also, we cannot switch to a mock object without changing the Client code (our SUT) Ok, so new is bad. What about using a Factory? ?
Instantiation with Factories This removes the dependency on the implementation But now there is a new association to ServiceFactory, which provides access to the subclasses ServiceImpl and MockServiceImpl ServiceFactory depends on these implementations, so as a result Client still has compile-time dependencies on implementation classes Additionally we need to write a lot of Factory boilerplate code Can we get rid off this new association? Yes, with dependency injection. This is also sometimes called Dependency Lookup ? ? ? !
Instantiation with Dependency Injection The basic idea behind dependency injection is to remove instantiations from the Client’s responsibility entirely and to let the implementation be supplied by an outside source via… … a constructor: public class Client { private Service service; public Client(Service service) { this.service=service; } …
Instantiation with Dependency Injection The basic idea behind dependency injection is to remove instantiations from the Client’s responsibility entirely and to let the implementation be supplied by an outside source via... … a constructor: public class Client { private Service service; public Client(Service service) { this.service=service; } … … a setter: public class Client { private Service service; public void setService(Service service) { this.service=service; } …
Instantiation with Dependency Injection Adding a constructor/setter gets rid off the previous associations but the problem of instantiation still is not solved – who creates the concrete instance and injects it? In order to really decouple object creation, we need a framework supplying the implementation subclasses Allows configuring binding of implementation classes to interfaces Still provides the advantages of the Factory Pattern. ?
Introduction to Dependency Injection This is what we have with factories: Comparison Bridge Runtime 3 additional associations that increase the coupling between objects High coupling is bad!
What we have and what we want
Introduction to Dependency Injection This is what we want: Comparison Bridge Runtime Client only depends on the interface Service Low coupling!
Introduction to Dependency Injection The dependency injection framework reduces the coupling: Comparison Bridge Runtime The Client now only knows the Service interface. There are no compile-time dependencies to implementations anymore The implementations are injected by the framework Binding (the selection of the “Impl” subclass to be instantiated for a certain interface) is also done by the framework Because there is no factory, the Client class can be more easily reused.
Dependency Injection Frameworks There are several frameworks for dependency injection For a list of frameworks (also in other programming languages) see http://en.wikipedia.org/wiki/Dependency_injection#Existing_frameworks Some examples for Java are: J2EE 5 Includes dependency injection as an alternative to JNDI Spring Uses XML to configure the binding of the specific subclass implementation to the interface Google Guice Uses Java 5 with annotations for configuration these bindings In the following we use Google Guice and explain its usage by code examples. JNDI: JNDI (Java Naming and Directory Interface)
Example: Existing Inventorysystem public class InventorySystem { private static String TALISKER = "Talisker"; private int totalStock; private Warehouse warehouse = new WarehouseImpl(); public void addToWarehouse(String item, int amount) { warehouse.add(item, amount); totalStock += amount; } public int getTotalStock() { return totalStock; public boolean processOrder(Order order) { order.fill(warehouse); return order.isFilled(); public static void main(String[] args) { InventorySystem inventorySystem = new InventorySystem(); inventorySystem.addToWarehouse(TALISKER, 50); boolean order1success = inventorySystem.processOrder(new OrderImpl(TALISKER, 50)); boolean order2success = inventorySystem.processOrder(new OrderImpl(TALISKER, 51)); System.out.println("Order1 succeeded? " + order1success + " - Order2 succeeded? " + order2success);
Example: InventorySystem with Guice public class InventorySystemDI { private static String TALISKER = "Talisker"; private int totalStock; @Inject private Warehouse warehouse; public void addToWarehouse(String item, int amount) { warehouse.add(item, amount); totalStock += amount; } public int getTotalStock() { return totalStock; public boolean processOrder(Order order) { order.fill(warehouse); return order.isFilled(); public static void main(String[] args) { Injector injector = Guice.createInjector(new ProductionModule()); InventorySystemDI inventorySystem = injector.getInstance(InventorySystemDI.class); inventorySystem.addToWarehouse(TALISKER, 50); boolean order1success = inventorySystem.processOrder(new OrderImpl(TALISKER, 50)); boolean order2success = inventorySystem.processOrder(new OrderImpl(TALISKER, 51)); System.out.println("Order1 succeeded? " + order1success + " - Order2 succeeded? " + order2success); Can you spot the difference to the old code?
Can you spot the difference to the old one? public class InventorySystemDI { private static String TALISKER = "Talisker"; private int totalStock; @Inject private Warehouse warehouse; public void addToWarehouse(String item, int amount) { warehouse.add(item, amount); totalStock += amount; } public int getTotalStock() { return totalStock; public boolean processOrder(Order order) { order.fill(warehouse); return order.isFilled(); public static void main(String[] args) { Injector injector = Guice.createInjector(new ProductionModule()); InventorySystemDI inventorySystem = injector.getInstance(InventorySystemDI.class); inventorySystem.addToWarehouse(TALISKER, 50); boolean order1success = inventorySystem.processOrder(new OrderImpl(TALISKER, 50)); boolean order2success = inventorySystem.processOrder(new OrderImpl(TALISKER, 51)); System.out.println("Order1 succeeded? " + order1success + " - Order2 succeeded? " + order2success); Notice there is no “new” here anymore! What is an injector? Here an injector is created that allows to specify bindings of implementations to interfaces. Uses a ProductionModule. See slide 41 These are the changes to the “Client”
What is an Injector? How do you get the Jam into the Krapfen? InventorySystem Injector filled with “Jam” (i.e. Warehouse)
Guice Modules: Configure the Bindings Guice uses the concept of a Module to bind a subclass implementation to an interface Here is the Guice Module ProductionModule that binds WarehouseImpl to Warehouse: public class ProductionModule implements Module { public void configure(Binder binder) { binder.bind(Warehouse.class).to(WarehouseImpl.class); }
4 Steps to use Guice Tell Guice what to inject using the @Inject annotation Constructor injection Method injection (for setter methods) Field injection Define Binding 3. Instantiate an Injector and tell it which Module to use (i.e. provide a list of available bindings) 4. Create instance classes needing injection by requesting an instance from the Injector (in our case: InventorySystem) For more details: http://code.google.com/p/google-guice/wiki/UserGuide
InventorySystem with Guice Code public class InventorySystemDI { private static String TALISKER = "Talisker"; private int totalStock; @Inject private Warehouse warehouse; public void addToWarehouse(String item, int amount) { warehouse.add(item, amount); totalStock += amount; } public int getTotalStock() { return totalStock; public boolean processOrder(Order order) { order.fill(warehouse); return order.isFilled(); public static void main(String[] args) { Injector injector = Guice.createInjector(new ProductionModule()); InventorySystemDI inventorySystem = injector.getInstance(InventorySystemDI.class); inventorySystem.addToWarehouse(TALISKER, 50); boolean order1success = inventorySystem.processOrder(new OrderImpl(TALISKER, 50)); boolean order2success = inventorySystem.processOrder(new OrderImpl(TALISKER, 51)); System.out.println("Order1 succeeded? " + order1success + " - Order2 succeeded? " + order2success);
Guice and Unit Testing How does this help us with unit testing? Remember – instead of this hard-coded dependency: public class InventorySystem { private Warehouse warehouse = new WarehouseImpl(); … } we now have: @Inject private Warehouse warehouse; As a result we are now able to write a unit test that binds warehouse to a mock To do this we define another Guice Module called TestModule. InventorySystem Injector filled with Warehouse
Configuring the Bindings The Guice module for the production code: public class ProductionModule implements Module { public void configure(Binder binder) { binder.bind(Warehouse.class).to(WarehouseImpl.class); } The Guice module for the unit test: public class TestModule implements Module { public void configure(Binder binder) { Warehouse warehouseMock = EasyMock.createMock(Warehouse.class); binder.bind(Warehouse.class).toInstance(warehouseMock); }
Unit Test of the InventorySystem using Guice and EasyMock public class InventorySystemDITest { private static String TALISKER = "Talisker"; private InventorySystemDI inventorySystem; private Injector injector; @Before public void setUp() throws Exception { injector = Guice.createInjector(new TestModule()); inventorySystem = injector.getInstance(InventorySystemDI.class); } @Test public void addToWarehouse() { Warehouse warehouseMock = injector.getInstance(Warehouse.class); warehouseMock.add(TALISKER, 50); EasyMock.replay(warehouseMock); inventorySystem.addToWarehouse(TALISKER, 50); assertEquals(inventorySystem.getTotalStock(), 50); EasyMock.verify(warehouseMock); Here we tell Guice to create an injector using TestModule, that binds Warehouse to a Warehouse Mock We let Guice instantiate the InventorySystem and the Warehouse in it Here we retrieve the mock Warehouse from the injector to use it during the test.
What have we learned? Simple unit tests allow to test state Use the Mock Object Pattern to unit test behavior Enforce low coupling with the Dependency Injection Pattern Are there other patterns applicable to testing? Yes, there are! Meszaros describes 68 testing patterns Gerard Meszaros: xUnit Test Patterns – Refactoring Test Code. Martin Fowler Signature Series, Addison-Wesley, 2007 For the rest of the lecture, we will highlight 4 Unit testing patterns: 4 stage testing pattern Inner class test pattern Reflection test pattern Test exception pattern. Test model as a new abstraction on the same level as the system model Dependency injection pattern (not only a testing pattern, good for your system health )
Where are we now? Unit testing with jUnit (Example) Mock object pattern (Example) Dependency injection pattern (not only a testing pattern) Unit testing patterns 4 stage testing pattern Inner class test pattern Reflection test pattern Test exception pattern Test model as a new abstraction on the same level as the system model Dependency injection pattern (not only a testing pattern, good for your system health )
Four-Stage Testing Pattern In the Four-Stage Testing Pattern a test driver (actor) executes a flow of events to interact with the SUT The flow of events can be into decomposed into four distinct phases that are executed in sequence. These phases are called setup, exercise, result validation and teardown Setup In this phase, we set up a socalled test fixture. In the test fixture we set up state and behavior that is needed to observe the SUT (such as using a mock object) Run the Test In this phase, we interact with the SUT, for example by calling a method (Often a little bit more Setup is required before calling the method) Validate We look at the results with respect to state and/or behavior of the test and determine whether the observed outcome is equal to the expected outcome. (Note: In the XP literature the incorrect term Verify is often used. Verification is not the same as validation) Teardown We put the SUT back into the state before the test was executed. In particular, we have to tear down any object we had to instantiate in the test fixture.
SUT (used in the following Slides) Assume we want to unit test the method encodePassword(). public class Authentication { private String key; public String getKey() { return key; } public void setKey(String key) { this.key = key; public String encodePassword(String password) throws ValidationException { String encodedPassword = ""; if (password == null || password.length() == 0) { throw new ValidationException("Password is empty"); // do the encoding return encodedPassword;
The 4 Phases: Setup, Exercise, Validate, Teardown A) Setup prerequisite objects: Declaration and initialization of authenticator key and user name public class AuthEncodingTest { Authentication authenticator; String name; @Before public void setUp() { authenticator = new Authentication(); authenticator.setKey("TESTKEY"); name = "user"; } @After public void tearDown() { authenticator.setKey(""); @Test public void encoding() throws ValidationException { String expectedKey = "fwe94t-gft5"; String observedKey = authenticator.encodePassword(name); assertEquals(expectedKey, observedKey); 4. Tear down the prerequisite objects The Test method B) Continued setup of prerequisite objects: expected key 2. Run the test: Call encodePassword(), the method being tested 3. Evaluate the results: For "user" and "TESTKEY" key we expect to get the key fwe94t-gft5"
Outline of the Lecture Unit testing with jUnit (Example) Mock object pattern (Example) Dependency injection pattern (not only a testing pattern) Unit testing patterns 4 stage testing pattern Inner class test pattern Reflection test pattern Test exception pattern Test model as a new abstraction on the same level as the system model Dependency injection pattern (not only a testing pattern, good for your system health )
Inner Class Test Pattern: Testing a protected method Problem: For the test a protected entity (field or method) needs to be accessed from another package Assume the encodePassword() method from the previous example is protected
Inner Class Test Pattern: Testing a protected method Solution: Introduce an anonymous inner class extending the original class and offer a public method delegating to the protected method of the original class ✔ public class AuthEncodingTest { ... class TestAuthentication extends Authentication { public String callEncodePassword(String password) throws ValidationException { // We can call a protected method from here return encodePassword(password); } @Test public void encoding() throws ValidationException { TestAuthentication authenticator = new TestAuthentication(); authenticator.setKey("TESTKEY"); String expectedKey = "fwe94t@#$5“; String name = "user"; // call the tested method by means of the Inner Class assertEquals(expectedKey, authenticator.callEncodePassword(name));
Outline of the Lecture Unit testing with jUnit (Example) Mock object pattern (Example) Dependency injection pattern (not only a testing pattern) 4 stage testing pattern Inner class test pattern Reflection test pattern Test exception pattern Test model as a new abstraction on the same level as the system model Dependency injection pattern (not only a testing pattern, good for your system health )
Reflection Test Pattern: Testing a Private Attribute Problem: There are some cases when it is necessary to test a private attribute Solution: Use reflection Example: Assume there is no getter for the private field “key” of the Authentication class but we need to access it for our test public class AuthPrivacyTest { @Test public void testKey() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Authentication auth = new Authentication(); String privateKey = "privateKey"; auth.setKey(privateKey); Class<? extends Authentication> cl = auth.getClass(); // get the reflected object Field field = cl.getDeclaredField("key"); // set accessible true field.setAccessible(true); assertEquals(field.get(auth), privateKey); } Get the class object for Authentication Get the field “key” Set the field to be accessible
Outline of the Lecture Unit testing with jUnit (Example) Mock object pattern (Example) Dependency injection pattern (not only a testing pattern) Unit Test patterns 4 stage testing pattern Inner class test pattern Reflection test pattern Test exception pattern Test model as a new abstraction on the same level as the system model Dependency injection pattern (not only a testing pattern, good for your system health )
Test Exception Pattern Problem: How to set up a test which is expected to result in an exception being raised The Authentication class for instance is expected to raise a ValidationException when confronted with an empty password Solution: The testing framework provides a mechanism for expecting exceptions Example: public class AuthExceptionTest { Authentication authenticator; @Before public void setUp() { authenticator = new Authentication(); } @Test(expected = ValidationException.class) public void encoding() throws ValidationException { authenticator.encodePassword(null); jUnit provides a mechanism for doing exception testing
Readings Brown & Tapolcsanyi: Mock Object Patterns. In Proceedings of the 10th Conference on Pattern Languages of Programs, 2003. Published online: http://hillside.net/plop/plop2003/papers.html EasyMock Framework http://easymock.org/, Last Viewed: Dec 2009 Martin Fowler: Inversion of Control Containers and the Dependency Injection pattern. http://martinfowler.com/articles/injection.html, Last Updated: 23 Jan 2004 Google Guice Framework http://code.google.com/p/google-guice/, Last Viewed: Dec 2009 Gerard Meszaros: xUnit Test Patterns – Refactoring Test Code. Martin Fowler Signature Series, Addison-Wesley, 2007 Typemock Ltd. Unit-Test Patterns for .NET - Part I. http://www.typemock.com/Docs/Unit_Test_Patterns_for_NET_Development_Part- 1.php, Last Update: July 2008 Johnson, R. and Foote, B.: Designing Reusable Classes. Journal of Object Oriented Programming 1, 2. SIGS Publication Group, (June/July 1988), pp22-35.
Additional Slides
History of Dependency Injection The basic idea behind dependency injection was was introduced by Johnson and Foote in 1988 in their paper “Designing Reusable Classes” In their section on frameworks they write: One important characteristic of a framework is that the methods defined by the user to tailor the framework will often be called from within the framework itself, rather than from the user's application code The framework often plays the role of the main program in coordinating and sequencing application activity. This inversion of control gives frameworks the power to serve as extensible skeletons The methods supplied by the user tailor the generic algorithms defined in the framework for a particular application The inversion of control principle was used by Martin Fowler who coined the term dependency injection in 2004. http://martinfowler.com/articles/injection.html
Additional Readings Rob Kuijt's Testing Blog about Test Design Patterns http://robkuijt.nl/ in particular http://robkuijt.nl/testdesignpatterns/index.php John D. McGregor, The Observer Test Patternhttp://www.cs.clemson.edu/~johnmc/joop/col18/col umn18.html Martin Fowler, Dependency Injection http://martinfowler.com/articles/injection.html
3 Additional Testing Patterns Unit testing with jUnit (Example) Mock object pattern (Example) Dependency injection pattern (not only a testing pattern) Unit Test patterns 4 stage testing pattern Inner class test pattern Reflection test pattern Test exception pattern Observer Test pattern Two MVC Test Patterns View-State Test Pattern Model-State Test Pattern Test model as a new abstraction on the same level as the system model Dependency injection pattern (not only a testing pattern, good for your system health )
Taxonomy for Testing Patterns Architectural Test Pattern -> Observer Test Pattern, Model State Test Pattern, View State Test Pattern
Observer Test Pattern The pattern is a variant of the observer pattern The test software needs to be notified when an action has happened. The observer test pattern allows a SUT using the observer pattern to be tested without being modified. The design describes a relationship between the application software and the test software. The pattern describes a set of interactions The Subject object treats the observer test object like any other observer, The Observer test object then accesses attributes of the Subject. This pattern solves a real problem. Interactions are a source of many errors in component-based software design Writing effective test software that examines the interactions is difficult The ObserverTest pattern provides an effective technique for constructing these tests
Observer Test Pattern (Warning: This slide is work in Progress) Applicable when the test needs to be notified when an action has happened or a state has been changed Assumption: The SUT is already using the observer pattern The observer test pattern just adds an ObserverTest class to the test model The Subject object treats the ObserverTest object like any other observer even though it is in the Test Model The ObserverTest object can access any attributes and any method of the Subject in the SUT! SUT Source http://robkuijt.nl/testdesignpatterns/show.php?zk=gang-of-four-test-design-patterns.txt Test model Additional Object in In the Test Model
Observer Test Pattern: Test model Object is accessing the SUT(Sequence Diagram) Work in Progress, To be done
Two Testing Patterns for MVC Recall the MVC Architectural Pattern It is vital that events are used for model notification changes and user gestures, such as clicking on a button. If you don't use events, the model breaks because you can't easily exchange the view to adjust the presentation to the particular presentation layer requirement. Furthermore, without events, objects become entangled. Also, events, such as managed by an event pool, allow for instrumentation and ease debugging. The only exception to this model that I have found in practice is that on occasion, a state change in the model might be captured by an event in the controller rather than the view. Some model changes, such as user authorization, are view-less but end up affecting other aspects of the controller Two MVC Test Patterns View-State Test Pattern Model-State Test Pattern Fromhttp://www.codeproject.com/KB/architecture/autp5.aspx#The%20Simple- Test%20Pattern3
The View-State Test Pattern This pattern tests that when the model state changes, the view changes state appropriately This test exercises only half of the MVC pattern--the model event notifications to the view, and the view management of those events. The controller is not tested in this test pattern.
The Model-State Test Pattern This pattern simulates user input by invoking a state change event such as "KeyUp", "Click", etc. Once we have verified application's performance with the View-State Pattern, we can progress to a more complicated one. The test pattern validates that the model state is changed appropriately and that the expected events fired. The test may require some setup on the model itself. It also treats the controller as a black box, however model state can be inspected to determine whether the controller is managing the model state appropriately.
jUnit 4 vs jUnit 3 jUnit 4 is completely based on annotations jUnit 4 No longer necessary to extend class TestCase Test-method names do not have to start with the prefix test. Instead they are annotated with the @Test annotation jUnit 4 jUnit 3 import org.junit.Test; public class CalculatorTest { @Test public void add() { .... } import junit.framework.TestCase; public class CalculatorTest extends TestCase { public void testadd() { .... }
Testing for Exceptions (jUnit 4 vs jUnit 3) public class CalculatorTest { @Test(expected=ArithmeticException.class) public void DivideByZero() { int n = 2/0; } public class CalculatorTest { public void testDivideByZero() { try { int n = 2/0; fail(„Division by zero!“); } catch (ArithmeticException success { assertNotNull(Success.getMessage()) } In jUnit 4, one can write the code that throws the exception and use an annotation to declare that the exception is expected. jUnit 3: Wrapping a try block around the code that throws the exception. Bad readability.
Writing Fixtures and Test Cases in JUnit 3.0 public class MyListTestCase extends TestCase { // … private MyList aList; private String anElement; public void setUp() { aList = new MyList(); anElement = “a string”; } public void testAdd() { aList.add(anElement); assertTrue(aList.size() == 1); assertTrue(aList.contains(anElement)); public void testRemove() { aList.remove(anElement); assertTrue(aList.size() == 0); assertFalse(aList.contains(anElement)); Test Fixture A test fixture is a set of instances and links that are used as a dummyenvironment for the test cases. By factoring out the initialization of the fixture into the setUp() method, fixtures can be reused between test cases.The tearDown() method is used to clean up after a test, so that the fixturecan be rebuilt from scratch for the next test case.The white paper from which these concepts are taken can be found at: http://junit.sourceforge.net/doc/cookbook/cookbook.htm Test Case Test Case
Test Suites in jUnit 3.0 Composite Pattern! public static Test suite() { TestSuite suite = new TestSuite(); suite.addTest(new MyListTest(“testAdd”)); suite.addTest(new MyListTest(“testRemove”)); return suite; } * Test run(TestResult) TestCase setUp() tearDown() testName:String runTest() TestSuite addTest() Composite Pattern!
Writing TestCases in JUnit 3.0 public class MyListTestCase extends TestCase { public MyListTestCase(String name) { super(name); } public void testAdd() { // Set up the test List aList = new MyList(); String anElement = “a string”; // Perform the test aList.add(anElement); // Check if test succeeded assertTrue(aList.size() == 1); assertTrue(aList.contains(anElement)); protected void runTest() { testAdd(); Test run(TestResult) MyListTestCase setUp() tearDown() runTest() testAdd() testRemove() TestResult TestCase setUp() tearDown() testName:String TestSuite addTest() MyList add() remove() contains() size() *
Example Code package income; public enum Position { BOSS, PROGRAMMER, SURFER } package income.exceptions; public class PositionException extends RuntimeException { private static final long serialVersionUID = 1L; public PositionException(String message) { super(message); package income.exceptions; public class CalcMethodException extends RuntimeException { private static final long serialVersionUID = 1L; public CalcMethodException(String message) { super(message); }
SUT (Unit to be tested) Methods under test Concrete Test case MyList * Test run(TestResult) TestResult SUT (Unit to be tested) MyList Methods under test add() remove() contains() size() Concrete Test case MyListTestCase testAdd testRemove TestCase run(TestResult) setUp() tearDown() testName:String runTest() TestSuite run(TestResult) addTest() MyList MyListTestCase add() remove() contains() size() setUp() tearDown() runTest() testAdd() testRemove()
GOF Design patterns used in the 4-Stage Test Pattern in JUnit 3.0 Composite Pattern Command Pattern * TestResult Test run(TestResult) TestCase run(TestResult) setUp() tearDown() testName:String runTest() TestSuite run(TestResult) addTest() Template Method Pattern ConcreteTestCase setUp() tearDown() runTest() Adapter Pattern SUT