TESTDRIVENDEVELOPMENT Unit testing basics and best practices Let’s get test infected!
@npathai on github Narendra Pathai 5 years of core development experience 4 years with unit testing 2 years with TDD Collaborator of Java Design Patterns repository Contributor to JUnit 4 and Java Hamcrest
@harshSE on github Harsh Patel 5 years of core development experience 3 years with unit testing 1 years with TDD Contributor to JMeter, Java Design Patterns
“TESTING CAN BE USED TO SHOW presence of bugs, NOTabsence” - Edsger Dijkstra
myths &misconceptions
Let’s write unit test cases because then there will be no bugsYayyy!! Myth 1
less bugs If unit testing is done properly then there will be Reality 1
wastes time I would rather write something that is useful because it Myth 2
saves time I must write tests today so that it tomorrow Reality 2
finding bugs Unit testing is just about Myth 3
Multi-faceted unit tests drive code design executable specification Reality 3
100% coverage I can be confident that code works only if there is Myth 4
n% coverage It’s perfectly fine to have if it gives the required confidence in the code Reality 4
production code Developers only write Myth 5 QA team does the testing
unit tests It’s developers who must write Reality 5
What is UNITTESTING?
tool { It’s a DESIGN CONFIDENCE REGRESSION
TESTS ARE FIRST CLIENTS OF CODE
TESTS ARE FIRST CLIENTS OF CODE I repeat
TEST PYRAMID
UNIT TESTS INTEGRATION TESTS END 2 END TESTS MANUAL TESTS CONFIDENCEINENTIRESYSTEM CONFIDENCEININDIVIDUALCHANGE EXECUTIONTIME RELIABILITY High Low Low High COST
ICE CREAM CONE Inverse of Test Pyramid More manual than unit tests Too costly to test what we don’t want Difficult to do in depth testing Often how testing is done
UNIT TESTS INTEGRATION TESTS END 2 END TESTS MANUAL TESTS
WHO WILL WRITE WHICH TESTS? Not important right now, a topic for some other day!
NAMINGCONVENTIONYou should call a spade a spade
HOW TO NAME TEST METHODS UnitOfWork_StateUnderTest_ExpectedBehavior behavior under test define current state of object Resultant state / event
HOW TO NAME TEST METHODS poppingAStack_whenEmpty_throwsException popping from stack when stack is empty because empty stack cannot be popped
TEST METHODS ON STEROIDS poppingAnEmptyStackThrowsException popping from stack when stack is empty because empty stack cannot be popped
BUILD THE RIGHTTHING poppingAnEmptyStackThrowsException { Object obj = stack.pop(); } are we building the right thing? are we building it right?
Writing the first TEST
xUnit frameworksare language specific Java jUnit .NET nUnit C++ CppTest Javascript qUnit *multiple frameworks per language are available
@Test is the way to define a new test case
@Before setup environment to run each test static Don’t even think about it.
@After cleanup resources after each test case
@BeforeClass setup expensive resources shared across all tests Think static
@AfterClass cleanup expensive resources shared across all tests
assertion A statement that is expected to be true at that point in code
assertion Passing test passes |assertion Failing test fails
assert keyword assert 2 + 1 == 3; Limited power Lower expressiveness
jUnit assertion More power * Better expressiveness assertXXX(...) methods
assertTrue(“woah!”, 2 + 1 == 3); assertion à la jUnit assertEquals(3, 2 + 1); assertArrayEquals([], []);
AARRANGE AACT AASSERT (given) (when) (then)
Defining a UNIT there is no correct way
UNIT is SUBJECTIVE a single class a group of related classes
When defining a UNIT DON’T CONSIDER INTERNAL STRUCTURE OF CLASS AS A UNIT IT TAKES EXPERIENCE TRIAL & ERROR
now introducing Hamcrest Matchers assertion on STEROIDS
assertThat(2 + 1, equalsTo(3)); expressive assertions assertThat(list, hasSize(3)); assertThat(list, contains(“a”));
assertThat(person, hasAge(30)); custom assertions assertThat(2, isEven()); assertThat(21, isDivisbleBy(3));
unexpected EXCEPTIONSnot all exceptions are unexpected
@Test poppingAnEmptyStackThrowsException() { try {... fail();} catch (SomeException e) { assertThat(e.getMessage(), ..); } } Using try...catch Error prone, we can do much better
@Test(expected = EmptyStackException.class) poppingAnEmptyStackThrowsException() Using @Test but cannot test exception message!
follow|RULES JUNIT ADDITION OR REDEFINITION OF TEST METHOD BEHAVIOR
ExpectedException rule @Rule public ExpectedException thrown = ExpectedException.none(); declares a rule reference rules must be public
poppingAnEmptyStackThrowsException() { thrown.expect(StackEmptyException.class); thrown.expectMessage(“stack is empty”); emptyStack.pop(); } ExpectedException rule
@Rule public TemporaryFolder folder = new TemporaryFolder(); folder.newFile(“myFile.txt”); folder.newFolder(“subFolder”); TemporaryFolder rule Automatically deletes temp files and directories
ExternalResource Timeout Custom More rules! No more leaked resources Fail tests after timeout Define custom rules
Run with (Runners) way to customize test processing & extend its purpose.
@RunWith A class level annotation that selects the runner to use for test case @RunWith(Suite.class) class of the runner to use
Hierarchical runner organize scenarios of the unit with nested classes/contexts
Suite runner organize several feature tests of a unit together
data >> tests test a system using data inputs
JUnitParams library Data driven testing from multiple types of sources @RunWith(JUnitParamsRunner.class)
PASS FROM ANNOTATION @Parameters({“a, A”, “b, B”}) @Test toUpperCaseConvertsCharactersToUpperCase(String in , String expectedOut)
PASS FROM METHOD @Parameters(method=”dataFor_toUpperCase”) @Test toUpperCaseConvertsCharactersToUpperCase(String in , String expectedOut)
PASS FROM CLASS @Parameters(source = DataForToUpperCase.class) @Test toUpperCaseConvertsCharactersToUpperCase(String in , String expectedOut)
PASS FROM FILE @FileParameters(“dataForToUpperCase.csv”) @Test toUpperCaseConvertsCharactersToUpperCase(String in , String expectedOut)
DON’T DO THIS AT HOME DIFFERENT SCENARIO - SAME DATA SOURCE DRIVING CONDITIONS FROM DATA
and the tools change us TOOLS We change the
EclEmma Plugin a plugin for code coverage in eclipse Infinitest Plugin a plugin that runs tests continuously in eclipse
Anti-PatternsEvery time you do this a kitten dies…
1 TEST CODE IS SECONDARY Anti-Pattern
1 PRODUCTIONcode = TESTcode Best Practice
2 REPEATING TEST CODE Anti-Pattern
2 KEEP CODE DRY Best Practice
3 TESTING internals or third party code Anti-Pattern
3TEST USING PUBLIC API Best Practice
4 MULTIPLESCENARIOS in a test Anti-Pattern
4 SINGLE SCENARIO per test Best Practice
5 CHANGEORDELETE tests* Anti-Pattern
5 ONLY IF CHANGE IN behavior Best Practice
Ending thoughts we have learnt a lot!
PRODUCTION CODE TEST CODE
PRODUCTION CODE TEST CODE contains nesting doesn’t contain nesting Is mostly imperative Is declarative takes more time to write takes less time to write
?

Test driven development - JUnit basics and best practices