How to improve your unit tests?
-
Upload
peter-modos -
Category
Technology
-
view
273 -
download
1
Transcript of How to improve your unit tests?
![Page 1: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/1.jpg)
SDL Proprietary and Confidential
How to improve your unit tests?
Peter Modos
12/12/2014
![Page 2: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/2.jpg)
2
Image placeholder
Click on image icon
Browse to image you want
to add to slide
Agenda
○ Intro
○ Why do we need unit tests
○ Good unit tests
○ Common mistakes
○ How to measure unit test quality
○ Ideas to improve tests
![Page 3: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/3.jpg)
Why to talk about unit tests?
![Page 4: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/4.jpg)
4
Why to talk about unit tests?
○ because there are plenty of bad unit tests out there • and some were written by us
![Page 5: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/5.jpg)
Why do we need unit tests?
![Page 6: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/6.jpg)
6
We do NOT write unit tests to
○ meet management’s expectation: have X% test coverage
Image source: http://www.codeproject.com/KB/cs/649815/codecoverage.png
![Page 7: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/7.jpg)
7
We do NOT write unit tests to
○ slow down product development
Image source: https://c1.staticflickr.com/3/2577/4166166862_788f971667.jpg
![Page 8: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/8.jpg)
8
We do NOT write unit tests to
○ break the build often
Image source: http://number1.co.za/wp-content/uploads/2014/12/oops-jenkins-f2e522ba131e713d5f0f2da19a7fb7da.png
![Page 9: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/9.jpg)
9
We do write unit tests to
○ verify the proper behavior of our software
○ be confident when we change something
○ have live documentation of the expected functionality
○ guide us while writing new code (TDD)
Image source: http://worldofdtcmarketing.com/wp-content/uploads/2013/12/change-same.jpg
![Page 10: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/10.jpg)
Good unit tests
![Page 11: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/11.jpg)
11
Good unit tests
○ properly test whole functionality of the target
○ focus only on the target class
○ use only public interface of the target class • do not depend on implementation details of the target
![Page 12: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/12.jpg)
12
Good unit tests
Image source: http://zeroturnaround.com/wp-content/uploads/2013/01/PUZZLE-1.jpg
![Page 13: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/13.jpg)
13
○ SUT: System Under Test • public interface
• implementation
○ public collaborators • constructor or other method param
○ private collaborators • implementation detail
• hidden dependency (e.g. static method call)
Never depend on the grey parts!
![Page 14: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/14.jpg)
14
Good unit tests - maintainable
○ written for the future
○ easy to read • good summary of expected functionality (documentation of the target)
• good abstraction (separating what and how to test)
○ easy to modify
![Page 15: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/15.jpg)
15
Good unit tests - test failure
○ failures are always reproducible
○ easy to find the reason of failure • informative error messages
○ fail when we change the behavior of code
○ fail locally: in the test class where functionality is broken
![Page 16: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/16.jpg)
16
Good unit tests - test execution
○ 100% deterministic
○ fast test run • quick feedback after a code change
• thousands of tests in few seconds
○ arbitrary order of execution
○ no side-effects and dependency on other tests
○ environment independent
○ do not use external dependencies • files, DB, network, other services
![Page 17: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/17.jpg)
Common mistakes
![Page 18: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/18.jpg)
18
Common mistakes
○ no tests
○ slow not executed
○ non-deterministic not executed
red build is tolerated
![Page 19: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/19.jpg)
19
Mistakes - part of the behavior is not tested
○ only happy execution path is tested • missing error cases
• exceptions from dependencies are not tested
○ edge cases are not tested • empty collection, negative number, etc.
○ returned value of target method is not verified
○ interactions with collaborators are not properly tested • e.g. returned values, correctness of parameters
○ high coverage, but no real verification
![Page 20: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/20.jpg)
20
Mistakes - dependency on internals of target
○ accessing internal state • increasing visibility of private fields
• creating extra getters
• using reflection
○ increasing visibility of private methods • because test is too complex
![Page 21: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/21.jpg)
21
Mistakes - hard to maintain
○ difficult to understand the tests • what is tested exactly
• how test is configured, executed
○ lot of duplication in test methods • too much details of irrelevant parts in main test method
○ difficult to follow up changes of target • interface change
• implementation change
![Page 22: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/22.jpg)
22
Mistakes - lack of isolation
○ between test cases • dependency between tests (shared state, static dependencies)
• one test failure makes the others failing
○ hard to handle the dependencies of the target class
sign of design issues in target
• implicit dependencies
• dependency chain
• need to configure static dependencies
![Page 23: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/23.jpg)
How to measure unit test quality?
![Page 24: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/24.jpg)
24
Measuring the quality of unit tests
○ code coverage measurement tools
○ mutation test for unit tests • Pitest (https://github.com/hcoles/pitest)
○ code review
○ next developer working on them later • or you
![Page 25: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/25.jpg)
Ideas to improve tests
![Page 26: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/26.jpg)
26
Listen to the tests!
○ why is it difficult to test? • change tested code accordingly
○ usually a sign of code smells • tight coupling
• too much responsibility
• something is too big, too complex (class, method)
• too much state change is possible (instead of immutability)
• etc.
![Page 27: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/27.jpg)
27
Use test doubles
○ to avoid dependency on collaborators’ real implementation • different opinions about how much to use
• mockist vs classical testing
• good summary on http://martinfowler.com/articles/mocksArentStubs.html
○ usage of a mocking library • speeds up test case writing
• enables behavior driven testing (vs state based testing)
○ but you can write your own stubs as well
![Page 28: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/28.jpg)
28
Mockist mindset
○ using mocks for all collaborators (dependencies)
○ clearly reduce the scope of the test • change in collaborator’s implementation will not influence the test
○ easier setup, full control over dependencies • dependencies are passed with DI (preferably as constructor parameters)
○ drawback • integration of real objects is not tested in unit level
• change in implementation might result change in tests
– but only when collaborators change
○ recommended library • Mockito: https://github.com/mockito/mockito
![Page 29: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/29.jpg)
29
Write tests first - TDD
○ lot of benefits • first thinking about functionality of target
• drives the design
– what dependencies are needed
– API of dependencies
○ very difficult to write tests afterwards • strong influence of existing code
• you will try to cover existing execution branches
• quite often the design is not (easily) testable
![Page 30: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/30.jpg)
30
Organizing tests
○ usually one test class per target class
○ one test method tests exactly one interaction/scenario
towards the target
○ test methods might be grouped by functionality/tested
method • by using inner classes
• by same method name prefix
![Page 31: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/31.jpg)
31
Naming test methods
○ let the name tell what is tested • clear summary what is tested in that scenario
○ do not worry if name is too long • better than explanation in comments
○ using underscore might increase readability
○ concrete format is less important, just be consistent
○ no ‘test’ prefix is needed • outdated convention of Junit
![Page 32: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/32.jpg)
32
Naming test methods
○ <what happens>_when_<conditions of test scenario>
○ <what happens>_for_<method name>_when_<conditions>
○ <method name>_with_<conditions>_does_<what happens>
![Page 33: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/33.jpg)
33
Naming test methods - example
@RunWith(Enclosed.class)
public class InMemoryAppTestRunRepositoryTest {
public static class GetAppTestRunMethod {
@Test
public void returnsAnEmptyOptional_when_testRunWasNotStoredWithTheRequestedId() {}
@Test
public void returnsProperTestRun_when_testRunWasStoredWithTheRequestedId() {}
@Test
public void returnsLastStoredTestRun_when_testRunWasStoredMultipleTimesWithTheRequestedId() {}
}
public static class GetAppTestRunsMethod {
@Test
public void returnsNoTestRuns_when_noTestRunsWereStored() {}
@Test
public void returnsLatestVersionOfAllStoredTestRuns_in_undefinedOrder_when_multipleTestRunsWereStored() {}
}
}
![Page 34: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/34.jpg)
34
Naming test methods - example
![Page 35: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/35.jpg)
35
Structure of a test method
@Test
public void name() {
<setup test conditions>
<call tested method(s) with meaningful parameters>
<verify returned value (if any)>
<verify expected interactions with collaborators (if needed)>
}
![Page 36: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/36.jpg)
36
Content of test methods
○ keep test methods short and abstract • important to see what is tested
• the how is tested can be hidden in helper methods
○ extract all unimportant details to helper methods • prefer more specific helper methods with talkative name and fewer params
• these can call more generic methods to avoid duplication
○ but all important activities and parameters shall be explicit in the test method
• call to the tested method(s)
• concrete scenario specific part of test setup
• verification of expected behavior
![Page 37: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/37.jpg)
37
Verification in test methods
○ types of verification • verify returned value of the tested method
• verify expected state change of the target object
• verify interaction with a collaborator
○ don’t have to repeat all verifications in all tests • different tests can concentrate on different part
• although if verification is compact, it won’t hurt to repeat
![Page 38: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/38.jpg)
38
Interactions with collaborators
○ important to distinguish between • setting up test conditions
– we want a collaborator to return a given value / throw an exception
• verifying expected interactions
– verify calls only when there are no returned values
– order of interactions is usually important
○ parameters of calls • always expect concrete param values when they are relevant (most of the time)
– expect the same object if you have the reference in the test
– use matchers if you don’t have the reference but know important properties of the
parameter
![Page 39: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/39.jpg)
39
Defining collaborators
○ we need an explicit reference to all collaborators • to be able to setup test conditions
• to be able to verify interactions
• if collaborators are created by the target object, we have no control over them
○ use dependency injection to pass them to the target object • as constructor parameter (preferred)
• as setter parameter
– dangerous because collaborators might change / not be initialized
○ if collaborators must be created by the target • pass factory object to create the dependency instead of direct instantiation
• we can mock the factory and have control over the returned collaborator
![Page 40: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/40.jpg)
40
Value objects in tests
○ inputs to the given test • constructor parameters of tested object
• parameters of the tested method
○ play important role in the expected behavior • influence returned value
• influence interactions with collaborators
○ often worth to create new classes for the entities • instead of having Strings for many parameters
• enjoy benefits of compile time type safety
○ if you have too many parameters • group together the belonging entities in a new class
![Page 41: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/41.jpg)
41
Value objects in tests
○ creation of value objects • use well named constants for very simple types/values
– simple objects, Strings, dummy numbers
• extract creation of instances to methods when their state is important
– when their state is read
– easier to change when constructor changes
– easier to change when you want to switch between mocked/real instances
• use mock fields when their state is not important
– when only their reference is used during interactions
![Page 42: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/42.jpg)
42
Matchers
○ can be applied for • verification of returned values
• verification of an interaction: expected parameters
• setting up test conditions: for which parameters do you want a given answer
○ useful when • you don’t have a reference to an expected object
• you want to verify only some aspects of the object
• you want to allow any value for an irrelevant parameter
○ recommended library • Hamcrest (https://github.com/hamcrest)
• you can compose matchers and build your own
![Page 43: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/43.jpg)
43
Avoid duplication in test classes
○ minimize the places where we have to change after • change in constructor/method parameters
• method renaming
• splitting a class
○ extract common logic to • test helper classes
• base test classes
• builder / utility classes in production code
![Page 44: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/44.jpg)
44
Example test case: test condition setup
@RunWith(MockitoJUnitRunner.class)
public static class RunToolMethod extends FvtRunnableTest {
@Test
public void
startsFvtProcess_with_properParamsTowardsTheStagingServer_on_targetFasQaTools_then_returnsSuccessResultAfterProcessFinishes_when_no
LiveServersInDeployment() {
FasTestDeployment deployment = createTestDeploymentWithServers(stagingServerMock, testerServerMock);
FvtRunnable runnable = createFvtRunnable(configMock, deployment);
fasQaToolClientFactoryReturnsFvtClientFor(testerServerMock, fasQaToolClientMock);
paramsConverterReturnsParamsForConfigAndServer(configMock, stagingServerMock, processParamsMock);
TestResult result = runnable.runTool(progressMock);
assertThat(result.isSuccessful(), equalTo(true));
InOrder inOrder = inOrder(fasQaToolClientMock);
inOrder.verify(fasQaToolClientMock).startTool(processParamsMock);
inOrder.verify(fasQaToolClientMock).waitUntilToolTerminates();
}
}
protected FvtRunnable createFvtRunnable(FvtConfig config, FasTestDeployment testDeployment) {
return new FvtRunnable(fasQaToolClientFactoryMock, paramsConverterMock, config, testDeployment);
}
![Page 45: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/45.jpg)
45
Example test case: tested method
@RunWith(MockitoJUnitRunner.class)
public static class RunToolMethod extends FvtRunnableTest {
@Test
public void
startsFvtProcess_with_properParamsTowardsTheStagingServer_on_targetFasQaTools_then_returnsSuccessResultAfterProcessFinishes_when_no
LiveServersInDeployment() {
FasTestDeployment deployment = createTestDeploymentWithServers(stagingServerMock, testerServerMock);
FvtRunnable runnable = createFvtRunnable(configMock, deployment);
fasQaToolClientFactoryReturnsFvtClientFor(testerServerMock, fasQaToolClientMock);
paramsConverterReturnsParamsForConfigAndServer(configMock, stagingServerMock, processParamsMock);
TestResult result = runnable.runTool(progressMock);
assertThat(result.isSuccessful(), equalTo(true));
InOrder inOrder = inOrder(fasQaToolClientMock);
inOrder.verify(fasQaToolClientMock).startTool(processParamsMock);
inOrder.verify(fasQaToolClientMock).waitUntilToolTerminates();
}
}
protected FvtRunnable createFvtRunnable(FvtConfig config, FasTestDeployment testDeployment) {
return new FvtRunnable(fasQaToolClientFactoryMock, paramsConverterMock, config, testDeployment);
}
![Page 46: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/46.jpg)
46
Example test case: verification
@RunWith(MockitoJUnitRunner.class)
public static class RunToolMethod extends FvtRunnableTest {
@Test
public void
startsFvtProcess_with_properParamsTowardsTheStagingServer_on_targetFasQaTools_then_returnsSuccessResultAfterProcessFinishes_when_no
LiveServersInDeployment() {
FasTestDeployment deployment = createTestDeploymentWithServers(stagingServerMock, testerServerMock);
FvtRunnable runnable = createFvtRunnable(configMock, deployment);
fasQaToolClientFactoryReturnsFvtClientFor(testerServerMock, fasQaToolClientMock);
paramsConverterReturnsParamsForConfigAndServer(configMock, stagingServerMock, processParamsMock);
TestResult result = runnable.runTool(progressMock);
assertThat(result.isSuccessful(), equalTo(true));
InOrder inOrder = inOrder(fasQaToolClientMock);
inOrder.verify(fasQaToolClientMock).startTool(processParamsMock);
inOrder.verify(fasQaToolClientMock).waitUntilToolTerminates();
}
}
protected FvtRunnable createFvtRunnable(FvtConfig config, FasTestDeployment testDeployment) {
return new FvtRunnable(fasQaToolClientFactoryMock, paramsConverterMock, config, testDeployment);
}
![Page 47: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/47.jpg)
47
Example test case: public collaborators
@RunWith(MockitoJUnitRunner.class)
public static class RunToolMethod extends FvtRunnableTest {
@Test
public void
startsFvtProcess_with_properParamsTowardsTheStagingServer_on_targetFasQaTools_then_returnsSuccessResultAfterProcessFinishes_when_no
LiveServersInDeployment() {
FasTestDeployment deployment = createTestDeploymentWithServers(stagingServerMock, testerServerMock);
FvtRunnable runnable = createFvtRunnable(configMock, deployment);
fasQaToolClientFactoryReturnsFvtClientFor(testerServerMock, fasQaToolClientMock);
paramsConverterReturnsParamsForConfigAndServer(configMock, stagingServerMock, processParamsMock);
TestResult result = runnable.runTool(progressMock);
assertThat(result.isSuccessful(), equalTo(true));
InOrder inOrder = inOrder(fasQaToolClientMock);
inOrder.verify(fasQaToolClientMock).startTool(processParamsMock);
inOrder.verify(fasQaToolClientMock).waitUntilToolTerminates();
}
}
protected FvtRunnable createFvtRunnable(FvtConfig config, FasTestDeployment testDeployment) {
return new FvtRunnable(fasQaToolClientFactoryMock, paramsConverterMock, config, testDeployment);
}
![Page 48: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/48.jpg)
48
Example test case: created collaborators
@RunWith(MockitoJUnitRunner.class)
public static class RunToolMethod extends FvtRunnableTest {
@Test
public void
startsFvtProcess_with_properParamsTowardsTheStagingServer_on_targetFasQaTools_then_returnsSuccessResultAfterProcessFinishes_when_no
LiveServersInDeployment() {
FasTestDeployment deployment = createTestDeploymentWithServers(stagingServerMock, testerServerMock);
FvtRunnable runnable = createFvtRunnable(configMock, deployment);
fasQaToolClientFactoryReturnsFvtClientFor(testerServerMock, fasQaToolClientMock);
paramsConverterReturnsParamsForConfigAndServer(configMock, stagingServerMock, processParamsMock);
TestResult result = runnable.runTool(progressMock);
assertThat(result.isSuccessful(), equalTo(true));
InOrder inOrder = inOrder(fasQaToolClientMock);
inOrder.verify(fasQaToolClientMock).startTool(processParamsMock);
inOrder.verify(fasQaToolClientMock).waitUntilToolTerminates();
}
private void fasQaToolClientFactoryReturnsFvtClientFor(TesterServer testerServer, FasQaToolClient returnedClient) {
fasQaToolClientFactoryReturnsClientFor(testerServer, PROCESS_FVT, returnedClient);
}
}
![Page 49: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/49.jpg)
49
Example test case: value objects
@RunWith(MockitoJUnitRunner.class)
public static class RunToolMethod extends FvtRunnableTest {
@Test
public void
startsFvtProcess_with_properParamsTowardsTheStagingServer_on_targetFasQaTools_then_returnsSuccessResultAfterProcessFinishes_when_no
LiveServersInDeployment() {
FasTestDeployment deployment = createTestDeploymentWithServers(stagingServerMock, testerServerMock);
FvtRunnable runnable = createFvtRunnable(configMock, deployment);
fasQaToolClientFactoryReturnsFvtClientFor(testerServerMock, fasQaToolClientMock);
paramsConverterReturnsParamsForConfigAndServer(configMock, stagingServerMock, processParamsMock);
TestResult result = runnable.runTool(progressMock);
assertThat(result.isSuccessful(), equalTo(true));
InOrder inOrder = inOrder(fasQaToolClientMock);
inOrder.verify(fasQaToolClientMock).startTool(processParamsMock);
inOrder.verify(fasQaToolClientMock).waitUntilToolTerminates();
}
}
![Page 50: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/50.jpg)
50
Example test case: created value objects
@RunWith(MockitoJUnitRunner.class)
public static class RunToolMethod extends FvtRunnableTest {
@Test
public void
startsFvtProcess_with_properParamsTowardsTheStagingServer_on_targetFasQaTools_then_returnsSuccessResultAfterProcessFinishes_when_no
LiveServersInDeployment() {
FasTestDeployment deployment = createTestDeploymentWithServers(stagingServerMock, testerServerMock);
FvtRunnable runnable = createFvtRunnable(configMock, deployment);
fasQaToolClientFactoryReturnsFvtClientFor(testerServerMock, fasQaToolClientMock);
paramsConverterReturnsParamsForConfigAndServer(configMock, stagingServerMock, processParamsMock);
TestResult result = runnable.runTool(progressMock);
assertThat(result.isSuccessful(), equalTo(true));
InOrder inOrder = inOrder(fasQaToolClientMock);
inOrder.verify(fasQaToolClientMock).startTool(processParamsMock);
inOrder.verify(fasQaToolClientMock).waitUntilToolTerminates();
}
private void paramsConverterReturnsParamsForConfigAndServer(FvtConfig config, Server targetServer,
Properties returnedProcessParams) {
when(paramsConverterMock.createProcessParams(config, targetServer)).thenReturn(returnedProcessParams);
}
}
![Page 51: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/51.jpg)
51
Example for helper methods public static class StartToolMethod extends FasQaToolClientTest {
@Test
public void startsProperProcess_on_daClient_with_passedParams() throws TestRunException {
…
client.startTool(toolParamsMock);
verifyProcessWasStartedOnDaClient(INSTANCE_NAME, TOOL_NAME, toolParamsMock);
}
private void verifyProcessWasStartedOnDaClient(String expectedInstanceName, String expectedProcess, Properties expectedParams) {
verifyProcessCommandWasExecutedOnDaClient(expectedInstanceName, expectedProcess, VERB_START, expectedParams);
}
}
public static class StopToolMethod extends FasQaToolClientTest {
@Test
public void stopsProperProcess_on_daClient() throws TestRunException {
…
client.stopTool();
verifyProcessWasStoppedOnDaClient(INSTANCE_NAME, TOOL_NAME);
}
private void verifyProcessWasStoppedOnDaClient(String expectedInstanceName, String expectedProcess) {
verifyProcessCommandWasExecutedOnDaClient(expectedInstanceName, expectedProcess, VERB_STOP, NO_PARAMS);
}
}
protected void verifyProcessCommandWasExecutedOnDaClient(String expectedInstanceName, String expectedProcess, String expectedVerb,
Properties expectedParams) {
verify(daClientMock).invokeProcessCommand(expectedInstanceName, expectedProcess, expectedVerb, expectedParams);
}
![Page 52: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/52.jpg)
52
Control the uncontrollable
○ you won’t have full control if your tested class • use Random
• use time related functionality (e.g. sleep(), now())
• is used by multiple threads
○ solution: do not use them directly • Random: pass as parameter, maybe hide behind an interface
• time: move all time related functionality behind an interface
– production code: use System time, real sleep
– test code: own time, non-blocking sleep
• multithreading
– use Runnable, Callable and Executor framework
– test separately the main activity in single thread
– custom test implementation of collaborators to control concurrent environment
![Page 53: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/53.jpg)
Recommended reading
![Page 54: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/54.jpg)
54
Recommended reading
books
Growing Object-Oriented Software Guided by Tests
(Steve Freeman, Nat Pryce)
The Art of Unit Testing: with Examples in .NET
(Roy Osherove)
xUnit Test Patterns: Refactoring Test Code
(Gerard Meszaros)
Test Driven Development: By Example
(Kent Beck)
![Page 55: How to improve your unit tests?](https://reader034.fdocuments.us/reader034/viewer/2022042716/55bfd6e9bb61ebef198b46d7/html5/thumbnails/55.jpg)
55
Recommended reading
blogs
Steve Freeman's blog
http://www.higherorderlogic.com
Kevin Rutherford's blog
http://silkandspinach.net
Google Testing on the Toilet
http://googletesting.blogspot.nl/search/label/TotT
Guide: Writing Testable Code (from Google)
http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf
… and plenty others