25
JUnit Test Fixture Pattern 6 May 2013 OSU CSE 1

JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

  • Upload
    vutu

  • View
    245

  • Download
    0

Embed Size (px)

Citation preview

Page 1: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

JUnit Test Fixture Pattern

6 May 2013 OSU CSE 1

Page 2: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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!

6 May 2013 OSU CSE 2

Page 3: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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); }

6 May 2013 OSU CSE 3

Page 4: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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); }

6 May 2013 OSU CSE 4

This kind of call of the constructor for the UUT needs to be changed (throughout the test fixture) if you

want to change the UUT.

Page 5: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

Single-Point Control Over Change

•  Question: How do we achieve the goal of single-point control over change in this situation?

6 May 2013 OSU CSE 5

Page 6: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

•  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

6 May 2013 OSU CSE 6

Single-Point Control Over Change

Page 7: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

The Code for a Test Case @Test public final void testPushEmpty() { Stack<String> s = this.constructorTest(); Stack<String> sExpected =

new Stack1L<>(); s.push("red"); sExpected.push("red");

assertEquals(sExpected, s); }

6 May 2013 OSU CSE 7

Instead of calling the UUT’s constructor directly here, you call

a method (perhaps named constructorTest), which then

calls the UUT’s constructor.

Page 8: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

Code for constructorTest Stack<String> constructorTest() { return new Stack1L<String>(); }

6 May 2013 OSU CSE 8

Page 9: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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");

assertEquals(sExpected, s); }

6 May 2013 OSU CSE 9

Instead of calling the UUT’s constructor directly here, you call

a method (perhaps named constructorRef) ...

Page 10: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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");

assertEquals(sExpected, s); }

6 May 2013 OSU CSE 10

... which then calls the constructor from either the UUT or a

reference implementation of the same interface.

Page 11: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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>(); }

6 May 2013 OSU CSE 11

Page 12: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

Isolating This Change Point

6 May 2013 OSU CSE 12

extends

Stack1LTest

test cases

constructorTest constructorRef

StackTest

Page 13: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

The Code of StackTest public abstract class StackTest { protected abstract Stack<String> constructorTest();

protected abstract Stack<String> constructorRef();

...

}

6 May 2013 OSU CSE 13

Page 14: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

The Code of StackTest public abstract class StackTest { protected abstract Stack<String> constructorTest();

protected abstract Stack<String> constructorRef();

...

}

6 May 2013 OSU CSE 14

StackTest is an abstract class now.

Page 15: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

The Code of StackTest public abstract class StackTest { protected abstract Stack<String> constructorTest();

protected abstract Stack<String> constructorRef();

...

}

6 May 2013 OSU CSE 15

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.

Page 16: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

The Code of StackTest public abstract class StackTest { protected abstract Stack<String> constructorTest();

protected abstract Stack<String> constructorRef();

...

}

6 May 2013 OSU CSE 16

abstract means that this method (called an abstract

method) must be overridden in some subclass (which is our

intent for Stack1LTest).

Page 17: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

The Code of Stack1LTest public class Stack1LTest extends StackTest { @Override

protected final Stack<String> constructorTest() { ...

}

@Override

protected final Stack<String> constructorRef() { ...

}

}

6 May 2013 OSU CSE 17

Page 18: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

The Code of Stack1LTest public class Stack1LTest extends StackTest { @Override

protected final Stack<String> constructorTest() { ...

}

@Override

protected final Stack<String> constructorRef() { ...

}

}

6 May 2013 OSU CSE 18

Incidentally, final here means that this method may not be

overridden in any subclass of Stack1LTest.

Page 19: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

The Code of Stack1LTest public class Stack1LTest extends StackTest { @Override

protected final Stack<String> constructorTest() { ...

}

@Override

protected final Stack<String> constructorRef() { ...

}

}

6 May 2013 OSU CSE 19

What code goes here?

Page 20: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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">

6 May 2013 OSU CSE 20

Page 21: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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">

6 May 2013 OSU CSE 21

What code must you write to give a variable this value?

Page 22: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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 */}

6 May 2013 OSU CSE 22

Page 23: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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 */}

6 May 2013 OSU CSE 23

This special Java varargs notation (yes, three dots, or

ellipsis, is part of the Java code here!) allows you to call this method with zero or more

arguments of type String.

Page 24: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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 */}

6 May 2013 OSU CSE 24

The method body is written as if args were an array of Strings of length equal to the number of

arguments in the call; and args is guaranteed not to be null.

Page 25: JUnit Test Fixture Pattern - Computer Science and …web.cse.ohio-state.edu/.../slides/03a.JUnit-Test-Fixture-Pattern.pdfJUnit Test Fixture Pattern 6 May 2013! OSU CSE! 1! The Problem

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> createFromArgsRef(

String... args) {/* body */}

6 May 2013 OSU CSE 25

In addition to createFromArgsTest

you will also want createFromArgsRef.