junit test fixture pattern
play

JUnit Test Fixture Pattern 15 January 2019 OSU CSE 1 The Problem - PowerPoint PPT Presentation

JUnit Test Fixture Pattern 15 January 2019 OSU CSE 1 The Problem In principle, a test fixture for a kernel class should be usable with any kernel class (UUT, or unit under test) that purports to implement the same interface


  1. JUnit Test Fixture Pattern 15 January 2019 OSU CSE 1

  2. The Problem • In principle, a test fixture for a kernel class should be usable with any kernel class (UUT, or “unit under test”) that purports to implement the same interface • However, you actually must modify the test fixture when you change the UUT, because each test case has to call the UUT’s constructor—whose name is that of the UUT! 15 January 2019 OSU CSE 2

  3. Example @Test public final void testPushEmpty() { Stack<String> s = new Stack1L<>(); Stack<String> sExpected = new Stack1L<>(); s.push("red"); sExpected.push("red"); assertEquals(sExpected, s); } 15 January 2019 OSU CSE 3

  4. Example @Test public final void testPushEmpty() { Stack<String> s = new Stack1L<>(); Stack<String> sExpected = new Stack1L<>(); s.push("red"); sExpected.push("red"); This kind of call of the constructor for the UUT needs to be changed assertEquals(sExpected, s); (throughout the test fixture) if you } want to change the UUT. 15 January 2019 OSU CSE 4

  5. Single-Point Control Over Change • Question : How do we achieve the goal of single-point control over change in this situation? 15 January 2019 OSU CSE 5

  6. Single-Point Control Over Change • Question : How do we achieve the goal of single-point control over change in this situation? • Answer : “Re-route” all UUT constructor calls to another method, which then calls the UUT constructor, so only the body of that one method needs to be changed to accommodate a different UUT 15 January 2019 OSU CSE 6

  7. The Code for a Test Case @Test public final void testPushEmpty() { Stack<String> s = this. constructorTest(); Stack<String> sExpected = new Stack1L<>(); s.push("red"); Instead of calling the UUT’s sExpected.push("red"); constructor directly here, you call assertEquals(sExpected, s); a method (perhaps named } constructorTest ), which then calls the UUT’s constructor. 15 January 2019 OSU CSE 7

  8. Code for constructorTest Stack<String> constructorTest() { return new Stack1L<String>(); } 15 January 2019 OSU CSE 8

  9. The Code for a Test Case @Test public final void testPushEmpty() { Stack<String> s = this. constructorTest(); Stack<String> sExpected = this. constructorRef(); s.push("red"); sExpected.push("red"); Instead of calling the UUT’s constructor directly here, you call assertEquals(sExpected, s); a method (perhaps named } constructorRef ) ... 15 January 2019 OSU CSE 9

  10. The Code for a Test Case @Test public final void testPushEmpty() { Stack<String> s = this. constructorTest(); Stack<String> sExpected = this. constructorRef(); s.push("red"); sExpected.push("red"); ... which then calls the constructor from either the UUT or a assertEquals(sExpected, s); reference implementation } of the same interface. 15 January 2019 OSU CSE 10

  11. Code for constructorRef • If there is no reference implementation: Stack<String> constructorRef() { return new Stack1L<String>(); } • If, say, Stack3 is available as a reference implementation: Stack<String> constructorRef() { return new Stack3<String>(); } 15 January 2019 OSU CSE 11

  12. Isolating This Change Point test cases StackTest extends constructorTest Stack1LTest constructorRef 15 January 2019 OSU CSE 12

  13. The Code of StackTest public abstract class StackTest { protected abstract Stack<String> constructorTest(); protected abstract Stack<String> constructorRef(); ... } 15 January 2019 OSU CSE 13

  14. The Code of StackTest public abstract class StackTest { protected abstract Stack<String> constructorTest(); protected abstract Stack<String> constructorRef(); StackTest is an abstract class now. ... } 15 January 2019 OSU CSE 14

  15. The Code of StackTest public abstract class StackTest { protected abstract Stack<String> constructorTest(); protected abstract Stack<String> constructorRef(); protected means that this method may be called or overridden ... in a subclass (which is our intent for Stack1LTest ), but may not even } be called from any other class declared outside this package. 15 January 2019 OSU CSE 15

  16. The Code of StackTest public abstract class StackTest { protected abstract Stack<String> constructorTest(); protected abstract Stack<String> constructorRef(); abstract means that this ... method (called an abstract method ) must be overridden in } some subclass (which is our intent for Stack1LTest ). 15 January 2019 OSU CSE 16

  17. The Code of Stack1LTest public class Stack1LTest extends StackTest { @Override protected final Stack<String> constructorTest() { ... } @Override protected final Stack<String> constructorRef() { ... } } 15 January 2019 OSU CSE 17

  18. The Code of Stack1LTest public class Stack1LTest extends StackTest { @Override protected final Stack<String> constructorTest() { ... } @Override Incidentally, final here means protected final Stack<String> constructorRef() { that this method may not be ... overridden in any subclass of } Stack1LTest . } 15 January 2019 OSU CSE 18

  19. The Code of Stack1LTest public class Stack1LTest extends StackTest { @Override protected final Stack<String> constructorTest() { ... } @Override What code goes here? protected final Stack<String> constructorRef() { ... } } 15 January 2019 OSU CSE 19

  20. Another Problem • In a typical test case, it takes many lines of code just to construct the values on which to run a test! • For instance, suppose you want to test a method with this Stack<String> value as input: <"a", "stack", "with", "stuff"> 15 January 2019 OSU CSE 20

  21. Another Problem • In a typical test case, it takes many lines of code just to construct the values on which What code must you write to give a variable this value? to run a test! • For instance, suppose you want to test a method with this Stack<String> value as input: <"a", "stack", "with", "stuff"> 15 January 2019 OSU CSE 21

  22. A Convenience Method • Consider this method in StackTest : /** * Creates and returns a Stack<String> * with the given entries. * @ensures * createFromArgsTest = [entries in args] */ private Stack<String> createFromArgsTest( String... args) {/* body */} 15 January 2019 OSU CSE 22

  23. A Convenience Method This special Java varargs • Consider this method in StackTest : notation (yes, three dots, or /** ellipsis, is part of the Java code here!) allows you to call this * Creates and returns a Stack<String> method with zero or more * with the given entries. arguments of type String . * @ensures * createFromArgsTest = [entries in args] */ private Stack<String> createFromArgsTest( String... args) {/* body */} 15 January 2019 OSU CSE 23

  24. A Convenience Method The method body is written as if • Consider this method in StackTest : args were an array of String s /** of length equal to the number of arguments in the call; and args is * Creates and returns a Stack<String> guaranteed not to be null . * with the given entries. * @ensures * createFromArgsTest = [entries in args] */ private Stack<String> createFromArgsTest( String... args) {/* body */} 15 January 2019 OSU CSE 24

  25. A Convenience Method • Consider this method in StackTest : In addition to createFromArgsTest /** you will also want * Creates and returns a Stack<String> createFromArgsRef . * with the given entries. * @ensures * createFromArgsTest = [entries in args] */ private Stack<String> createFromArgsRef( String... args) {/* body */} 15 January 2019 OSU CSE 25

Recommend


More recommend