SlideShare une entreprise Scribd logo
1  sur  36
Mocking without
the Hangover
Jan Wloka
jan.wloka@quatico.com
@crashtester
Small Engineering Shop in Zurich
Small Engineering Shop in Zurich
http://
jobs.quatico.com
Mocks,
seriously?!
We don’t like mocks
Mocking is fundamentally evil. It encourage you to write bad, poorly
factored code, not-very-functional code. It encourages you to avoid
standing up as much of your system as possible during integration testing.
Finally, all too often at the end of all that mocking all you end up with are some
really well tested Mocks nested N! levels. In other words, mocking produces
a bunch of useless code that costs money and time to maintain.
Mocking is Evil
— Eric Merritt { http://blog.ericbmerritt.com }
“
“”
We don’t like mocks
They had written a series of tests for the business logic layer that completely
mocked out the data access layer. Normally this is fine as you don’t want to
actually hit a database in a unit test, but what they had done was actually
mock out the majority of their business logic which meant the tests
were not doing anything useful at all.
All Your Mocks are Evil!!
— Stephen Haunts { https://stephenhaunts.com }
“
“”
We don’t like mocks
If I could just mock out all of the EJB stuff, I'd be sitting pretty. […]
Not even an hour had passed and I needed to mock
java.sql.Connection. 40 methods! Getters and setters for every parameter,
return value and counter for every method? .... hmmmm .... thinking this
through a little .... the reason we make the attributes private is for the
sake of encapsulation - to hide how things are done on the inside so that
we can change our business logic later without breaking a bunch of stuff that
decided to tap into our innards. But that doesn't really apply to a mock,
does it?
Evil Unit Testing
— Paul Wheaton { http://www.javaranch.com }
“
“”
We don’t like mocks
I’ve never been a big fan of mocking frameworks, for one simple reason.
Simple stubbing relies on assumptions on the functioning of the mocked
part of your system that rarely match reality, for no one is going to look
at all the documentation of an API and decompile the code when writing a
one-line stub.
Mocking considered evil
— Sebastien Lambla { https://serialseb.com/blog/ }
“
“”
I’ve been there…
~10’000 Unit tests
~80% coverage
ø refactoring possible
Let’s talk!
about your experience
Why mocking?
Why mocking?
Unit testing at scale
Key: Test in Isolation.
Simple: Arrange. Act. Assert.
@Test

public void setPropertiesWithValidPropertiesYieldsSameObject()
throws Exception {

Properties expected = new Properties();



Item testObj = new Item("/path").setProperties(expected);



assertSame(expected, testObj.getProperties());

}
@Test
public void testGetImageLegendWithSourceAndCaptionReturnsBoth() throws Exception {
ResourceResolver resolver = new ResourceResolverImpl(client);
createPage(“/content/foobar”, new Properties(), PageType.PRESENCE.getTemplate());
createPage(“/content/foobar/ko”, new Properties(), PageType.LANGUAGE.getTemplate());
createPage(“/content/foobar/ko/home", new Properties(), PageType.HOME.getTemplate());
createPage(“/content/foobar/ko/home/content", new Properties(), PageType.DETAIL.getTemplate());
Resource contentPage = resolver.getResource(“/content/foobar/ko/home/content");
createResource(contentPage.getPath() + "/jcr:content/textimage", new Properties());
Resource target = resolver.getResource(contentPage.getPath() + "/jcr:content/textimage");
Properties imageProps = new Properties()
.append("source", "<sourceValue>")
.append("caption", "titleValue")
.append("sling:resourceType", ComponentType.IMAGE)
.append(JCR_LASTMODIFIED, new Time().format(DateFormat.GMT))
.append(JCR_LAST_MODIFIED_BY, "admin");
createResource(contentPage.getPath() + "/jcr:content/textimage/image", imageProps);
TextImageController testObj = new TextImageController().setup(createContext(target, contentPage));
assertEquals("titleValue<br />&lt;sourceValue&gt;", testObj.getImageLegend());
}
Key: Test in Isolation.
@Test
public void testGetImageLegendWithSourceAndCaptionReturnsBoth() throws Exception {
ResourceResolver resolver = new ResourceResolverImpl(client);
createPage(“/content/foobar”, new Properties(), PageType.PRESENCE.getTemplate());
createPage(“/content/foobar/ko”, new Properties(), PageType.LANGUAGE.getTemplate());
createPage(“/content/foobar/ko/home", new Properties(), PageType.HOME.getTemplate());
createPage(“/content/foobar/ko/home/content", new Properties(), PageType.DETAIL.getTemplate());
Resource contentPage = resolver.getResource(“/content/foobar/ko/home/content");
createResource(contentPage.getPath() + "/jcr:content/textimage", new Properties());
Resource target = resolver.getResource(contentPage.getPath() + "/jcr:content/textimage");
Properties imageProps = new Properties()
.append("source", "<sourceValue>")
.append("caption", "titleValue")
.append("sling:resourceType", ComponentType.IMAGE)
.append(JCR_LASTMODIFIED, new Time().format(DateFormat.GMT))
.append(JCR_LAST_MODIFIED_BY, "admin");
createResource(contentPage.getPath() + "/jcr:content/textimage/image", imageProps);
TextImageController testObj = new TextImageController().setup(createContext(target, contentPage));
assertEquals("titleValue<br />&lt;sourceValue&gt;", testObj.getImageLegend());
}
Arrange
Key: Test in Isolation.
@Test
public void testGetImageLegendWithSourceAndCaptionReturnsBoth() throws Exception {
ResourceResolver resolver = new ResourceResolverImpl(client);
createPage(“/content/foobar”, new Properties(), PageType.PRESENCE.getTemplate());
createPage(“/content/foobar/ko”, new Properties(), PageType.LANGUAGE.getTemplate());
createPage(“/content/foobar/ko/home", new Properties(), PageType.HOME.getTemplate());
createPage(“/content/foobar/ko/home/content", new Properties(), PageType.DETAIL.getTemplate());
Resource contentPage = resolver.getResource(“/content/foobar/ko/home/content");
createResource(contentPage.getPath() + "/jcr:content/textimage", new Properties());
Resource target = resolver.getResource(contentPage.getPath() + "/jcr:content/textimage");
Properties imageProps = new Properties()
.append("source", "<sourceValue>")
.append("caption", "titleValue")
.append("sling:resourceType", ComponentType.IMAGE)
.append(JCR_LASTMODIFIED, new Time().format(DateFormat.GMT))
.append(JCR_LAST_MODIFIED_BY, "admin");
createResource(contentPage.getPath() + "/jcr:content/textimage/image", imageProps);
TextImageController testObj = new TextImageController().setup(createContext(target, contentPage));
assertEquals("titleValue<br />&lt;sourceValue&gt;", testObj.getImageLegend());
}
Arrange
Act
Key: Test in Isolation.
@Test
public void testGetImageLegendWithSourceAndCaptionReturnsBoth() throws Exception {
ResourceResolver resolver = new ResourceResolverImpl(client);
createPage(“/content/foobar”, new Properties(), PageType.PRESENCE.getTemplate());
createPage(“/content/foobar/ko”, new Properties(), PageType.LANGUAGE.getTemplate());
createPage(“/content/foobar/ko/home", new Properties(), PageType.HOME.getTemplate());
createPage(“/content/foobar/ko/home/content", new Properties(), PageType.DETAIL.getTemplate());
Resource contentPage = resolver.getResource(“/content/foobar/ko/home/content");
createResource(contentPage.getPath() + "/jcr:content/textimage", new Properties());
Resource target = resolver.getResource(contentPage.getPath() + "/jcr:content/textimage");
Properties imageProps = new Properties()
.append("source", "<sourceValue>")
.append("caption", "titleValue")
.append("sling:resourceType", ComponentType.IMAGE)
.append(JCR_LASTMODIFIED, new Time().format(DateFormat.GMT))
.append(JCR_LAST_MODIFIED_BY, "admin");
createResource(contentPage.getPath() + "/jcr:content/textimage/image", imageProps);
TextImageController testObj = new TextImageController().setup(createContext(target, contentPage));
assertEquals("titleValue<br />&lt;sourceValue&gt;", testObj.getImageLegend());
}
Arrange
Act
Assert
Key: Test in Isolation.
Dependencies vs. Isolation
Sandbox
Test Object
{state, behavior}
Direct
Collaborator
{state, behavior}
Indirect
Collaborator
{state, behavior}
Parent
{state, behavior}
Data
{state}
Event
{state,
behavior}
Arrange: Dependencies?
• What: State, Behavior[, Event and Data]
• Where: Local, Parent, External
• How:
• Explicit/Implicit: Is it injectable?
• Direct/Indirect: Do I depend on it directly?
• Accessible/Inaccessible: Is it static, final etc.?
Mockito 101
• Mock: Empty Object: No state, No behavior.



ItemService service = mock(ItemService.class);
• Stub: Specify Behavior



when(service.load(“index.html”)).thenReturn(“foobar”);
• Spy: Real Object: Real / partial state and behavior



ItemService service = spy(new ItemService());

doReturn(“foobar”).when(service).load(“index.html”);
Partial Mocking
• Gradually mock behaviour
• mock(FooBar.class)
• mock(FooBar.class, CALLS_REAL_METHODS)
• spy(new FooBar())
Default Answers
public IProjectLink aProjectLink(String label, String linkType) {
IProjectLink result= mock(IProjectLink.class, RETURNS_SMART_NULLS);
when(result.getLabel()).thenReturn(label);
when(result.getLinkType()).thenReturn(linkType);
return result;
}
• Other default answers:
• CALLS_REAL_METHODS (partial mocking)
• RETURNS_MOCKS (mock return values)
• RETURNS_DEEP_STUBS (stub transitively)
• RETURNS_DEFAULTS (default answer)
Stub it in or out?
when(mock.methodCall(Matcher.anyString())).thenReturn(“value”);
when(mock.methodCall(Matcher.anyString())).then(new Answer() {});
when(mock.methodCall(Matcher.anyString())).thenThrow(Exception.class);
doReturn(“value”).when(mock).methodCall(Matcher.anyString());
doAnswer(new Answer() {}).when(mock).methodCall(Matcher.anyString());
doThrow(Exception.class).when(mock).methodCall(Matcher.anyString());
obj method argument matchers value / answer
obj method argument matchersvalue / answer
Danger: Partial Mocks
public String load(String path) throws FooException {
// ...
// method behavior
//...
return result;
}
doReturn().when() ——>
when().thenReturn() ——>
public class DbTest {

@Mock

private IPropertiesStore mockedStore;

@InjectMocks

private DB testObj;

@Before

public void setUp() throws Exception {

testObj = DB.init();

MockitoAnnotations.initMocks(this);

}

InjectBehavior
InjectState
Assert: Effects?
• Assert genuine effects:
• Returned values. Changed state. Exceptions.



assertEquals(), assertNotNull(),
@Test(expect = …)
• Mocks/spies verify behavior:
• Called methods. Count calls. Capture arguments. 



verify(mock,times(2)).methodFoo(Matchers.anyString())
Verify: calls w/ args
@Test
public void getContentShouldManageInputStreamsProperly() throws Exception {
InputStream inputStream= spy(new FileInputStream(new File("tmp/test.txt")));
Response testObj= spy(new Response(
HttpStatus.SC_OK,
Collections.emptyMap(),
inputStream));
testObj.getContent();
// way too many examples
verify(inputStream, times(2)).close();
verify(inputStream, atMost(2)).close();
verify(inputStream, timeout(100).atLeastOnce()).close();
verify(inputStream, never()).reset();
verify(testObj).getResponseHeader(anyString());
verify(testObj).getResponseHeader(eq(HttpUtil.CONTENT_TYPE));
}
Matchers make it fit
๏ org.mockito.Matchers, e.g.:
• any(Class<T>), anyBoolean()
• isA(Class<T>), eq(T), refEq(T, String…)
• isNull(Class<T>), notNull()
• same(T), contains(String)
• matches(String)
๏ Use org.hamcrest.Matchers with, e.g.:
• argThat(Matcher<T>)
• charThat(Matcher<Char>),
• booleanThat(Matcher<Boolean>)
Let’s code!
Add unit tests
createItem(Item) : Item
getItem(String) : Item
updateItem(Item) : Item
ItemService
+ init() : DB
+ get(String) : Item
+ store(Item) : DB
+ delete(String) : DB
+ exists(Item) : boolean
- singleton : DB
DB
+ load(String) : Properties
+ save(String, Properties) : IPropertiesStore
+ remove(String) : IPropertiesStore
IPropertiesStore
+ load(String) : Properties
+ save(String, Properties) : IPropertiesStore
+ remove(String) : IPropertiesStore
- data : Map<String, Properties>
InMemoryPropertiesStore
datastorage
+ getPath() : String
+ getProperties() : Properties
+ setProperties(Properties) : Item
- path : String
Item
+ hasProperty(Object) : boolean
+setValue(Object, Object) : Properties
+ getValue(Object key) : Object
- data : Map<Object, Object>
Properties
properties
Get the Code.
https://github.com/jwloka/mocktesting/
git clone ssh://git@github.com/jwloka/mocktesting.git
Run it.
$ mvn clean install
Write valuable tests.
• Go through the code add unit tests
• Think about what to mock and why?
• Where to start? Follow the hints in the code!
• Remember: You are allowed to change the code!
Get the solution.
git checkout tags/v2
Mocks, revisited
• Can Mocking cause poorly factored code?
• Need for mocks: design feedback
• Be aware deeply nested mocks!
• Can Mocking break encapsulation?
• Mocked internal state
• Need for behavior verification
• Can Mocking create artificial behavior?
• Mocks with state are dangerous
• Use stubs with canned values
• Can Mocking reduce test value?
• Mock direct collaborators only
• Under-specify with matchers
No Hangover, please!
Rules of the road:
• Try to use the real thing
• Mocks are for direct collaborators
• Never mock the test object
• Be aware of deeply-nested mocks, e.g.
RETURN_DEEP_STUBS
• Stateless mocks, with stubs to return
canned values
• Don’t verify on non public API
• Under-specify in mocks and stubs with
matchers.
Ready. Set. Go.
• Unit Testing In The Real World
• More guidance. More
examples.
• How to write unit tests?
• Measure test coverage.
Thank You.
jan.wloka@quatico.com
@crashtester

Contenu connexe

En vedette

Writing Well-Behaved Unix Utilities
Writing Well-Behaved Unix UtilitiesWriting Well-Behaved Unix Utilities
Writing Well-Behaved Unix UtilitiesRob Miller
 
Circuit breakers for Java: Failsafe, Javaslang-Circuitbreaker, Hystrix and Ve...
Circuit breakers for Java: Failsafe, Javaslang-Circuitbreaker, Hystrix and Ve...Circuit breakers for Java: Failsafe, Javaslang-Circuitbreaker, Hystrix and Ve...
Circuit breakers for Java: Failsafe, Javaslang-Circuitbreaker, Hystrix and Ve...Micha Kops
 
To Microservices and Beyond
To Microservices and BeyondTo Microservices and Beyond
To Microservices and BeyondMatt Stine
 
Mockito vs JMockit, battle of the mocking frameworks
Mockito vs JMockit, battle of the mocking frameworksMockito vs JMockit, battle of the mocking frameworks
Mockito vs JMockit, battle of the mocking frameworksEndranNL
 
Using Hystrix to Build Resilient Distributed Systems
Using Hystrix to Build Resilient Distributed SystemsUsing Hystrix to Build Resilient Distributed Systems
Using Hystrix to Build Resilient Distributed SystemsMatt Jacobs
 
(ARC317) Maintaining a Resilient Front Door at Massive Scale | AWS re:Invent ...
(ARC317) Maintaining a Resilient Front Door at Massive Scale | AWS re:Invent ...(ARC317) Maintaining a Resilient Front Door at Massive Scale | AWS re:Invent ...
(ARC317) Maintaining a Resilient Front Door at Massive Scale | AWS re:Invent ...Amazon Web Services
 
How we sleep well at night using Hystrix at Finn.no
How we sleep well at night using Hystrix at Finn.noHow we sleep well at night using Hystrix at Finn.no
How we sleep well at night using Hystrix at Finn.noHenning Spjelkavik
 
Microservice Architecture
Microservice ArchitectureMicroservice Architecture
Microservice Architecturetyrantbrian
 
Microservices vs. The First Law of Distributed Objects - GOTO Nights Chicago ...
Microservices vs. The First Law of Distributed Objects - GOTO Nights Chicago ...Microservices vs. The First Law of Distributed Objects - GOTO Nights Chicago ...
Microservices vs. The First Law of Distributed Objects - GOTO Nights Chicago ...Phil Calçado
 
DDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFrameworkDDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFrameworkbanq jdon
 
Towards complex adaptive architectures
Towards complex adaptive architecturesTowards complex adaptive architectures
Towards complex adaptive architecturesUwe Friedrichsen
 
Designing, building, testing and deploying microservices. A stairway to heave...
Designing, building, testing and deploying microservices. A stairway to heave...Designing, building, testing and deploying microservices. A stairway to heave...
Designing, building, testing and deploying microservices. A stairway to heave...Codemotion
 
Thirty months of microservices. Stairway to heaven or highway to hell? - Sand...
Thirty months of microservices. Stairway to heaven or highway to hell? - Sand...Thirty months of microservices. Stairway to heaven or highway to hell? - Sand...
Thirty months of microservices. Stairway to heaven or highway to hell? - Sand...Codemotion
 
Resilient Functional Service Design
Resilient Functional Service DesignResilient Functional Service Design
Resilient Functional Service DesignUwe Friedrichsen
 
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...Chris Richardson
 

En vedette (20)

Writing Well-Behaved Unix Utilities
Writing Well-Behaved Unix UtilitiesWriting Well-Behaved Unix Utilities
Writing Well-Behaved Unix Utilities
 
Circuit breakers for Java: Failsafe, Javaslang-Circuitbreaker, Hystrix and Ve...
Circuit breakers for Java: Failsafe, Javaslang-Circuitbreaker, Hystrix and Ve...Circuit breakers for Java: Failsafe, Javaslang-Circuitbreaker, Hystrix and Ve...
Circuit breakers for Java: Failsafe, Javaslang-Circuitbreaker, Hystrix and Ve...
 
To Microservices and Beyond
To Microservices and BeyondTo Microservices and Beyond
To Microservices and Beyond
 
Mockito vs JMockit, battle of the mocking frameworks
Mockito vs JMockit, battle of the mocking frameworksMockito vs JMockit, battle of the mocking frameworks
Mockito vs JMockit, battle of the mocking frameworks
 
Using Hystrix to Build Resilient Distributed Systems
Using Hystrix to Build Resilient Distributed SystemsUsing Hystrix to Build Resilient Distributed Systems
Using Hystrix to Build Resilient Distributed Systems
 
Mocking
MockingMocking
Mocking
 
(ARC317) Maintaining a Resilient Front Door at Massive Scale | AWS re:Invent ...
(ARC317) Maintaining a Resilient Front Door at Massive Scale | AWS re:Invent ...(ARC317) Maintaining a Resilient Front Door at Massive Scale | AWS re:Invent ...
(ARC317) Maintaining a Resilient Front Door at Massive Scale | AWS re:Invent ...
 
How we sleep well at night using Hystrix at Finn.no
How we sleep well at night using Hystrix at Finn.noHow we sleep well at night using Hystrix at Finn.no
How we sleep well at night using Hystrix at Finn.no
 
Microservice Architecture
Microservice ArchitectureMicroservice Architecture
Microservice Architecture
 
Microservices vs. The First Law of Distributed Objects - GOTO Nights Chicago ...
Microservices vs. The First Law of Distributed Objects - GOTO Nights Chicago ...Microservices vs. The First Law of Distributed Objects - GOTO Nights Chicago ...
Microservices vs. The First Law of Distributed Objects - GOTO Nights Chicago ...
 
DDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFrameworkDDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFramework
 
Towards complex adaptive architectures
Towards complex adaptive architecturesTowards complex adaptive architectures
Towards complex adaptive architectures
 
Production-ready Software
Production-ready SoftwareProduction-ready Software
Production-ready Software
 
Designing, building, testing and deploying microservices. A stairway to heave...
Designing, building, testing and deploying microservices. A stairway to heave...Designing, building, testing and deploying microservices. A stairway to heave...
Designing, building, testing and deploying microservices. A stairway to heave...
 
Thirty months of microservices. Stairway to heaven or highway to hell? - Sand...
Thirty months of microservices. Stairway to heaven or highway to hell? - Sand...Thirty months of microservices. Stairway to heaven or highway to hell? - Sand...
Thirty months of microservices. Stairway to heaven or highway to hell? - Sand...
 
Resilient Functional Service Design
Resilient Functional Service DesignResilient Functional Service Design
Resilient Functional Service Design
 
Resilience with Hystrix
Resilience with HystrixResilience with Hystrix
Resilience with Hystrix
 
Watch your communication
Watch your communicationWatch your communication
Watch your communication
 
Life, IT and everything
Life, IT and everythingLife, IT and everything
Life, IT and everything
 
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...
 

Dernier

AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park masabamasaba
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationJuha-Pekka Tolvanen
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024VictoriaMetrics
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxAnnaArtyushina1
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareJim McKeeth
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...masabamasaba
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...masabamasaba
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...Jittipong Loespradit
 

Dernier (20)

AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 

Mocking without the Hangover

  • 1. Mocking without the Hangover Jan Wloka jan.wloka@quatico.com @crashtester
  • 3. Small Engineering Shop in Zurich http:// jobs.quatico.com
  • 5. We don’t like mocks Mocking is fundamentally evil. It encourage you to write bad, poorly factored code, not-very-functional code. It encourages you to avoid standing up as much of your system as possible during integration testing. Finally, all too often at the end of all that mocking all you end up with are some really well tested Mocks nested N! levels. In other words, mocking produces a bunch of useless code that costs money and time to maintain. Mocking is Evil — Eric Merritt { http://blog.ericbmerritt.com } “ “”
  • 6. We don’t like mocks They had written a series of tests for the business logic layer that completely mocked out the data access layer. Normally this is fine as you don’t want to actually hit a database in a unit test, but what they had done was actually mock out the majority of their business logic which meant the tests were not doing anything useful at all. All Your Mocks are Evil!! — Stephen Haunts { https://stephenhaunts.com } “ “”
  • 7. We don’t like mocks If I could just mock out all of the EJB stuff, I'd be sitting pretty. […] Not even an hour had passed and I needed to mock java.sql.Connection. 40 methods! Getters and setters for every parameter, return value and counter for every method? .... hmmmm .... thinking this through a little .... the reason we make the attributes private is for the sake of encapsulation - to hide how things are done on the inside so that we can change our business logic later without breaking a bunch of stuff that decided to tap into our innards. But that doesn't really apply to a mock, does it? Evil Unit Testing — Paul Wheaton { http://www.javaranch.com } “ “”
  • 8. We don’t like mocks I’ve never been a big fan of mocking frameworks, for one simple reason. Simple stubbing relies on assumptions on the functioning of the mocked part of your system that rarely match reality, for no one is going to look at all the documentation of an API and decompile the code when writing a one-line stub. Mocking considered evil — Sebastien Lambla { https://serialseb.com/blog/ } “ “”
  • 9. I’ve been there… ~10’000 Unit tests ~80% coverage ø refactoring possible
  • 13. Key: Test in Isolation. Simple: Arrange. Act. Assert. @Test
 public void setPropertiesWithValidPropertiesYieldsSameObject() throws Exception {
 Properties expected = new Properties();
 
 Item testObj = new Item("/path").setProperties(expected);
 
 assertSame(expected, testObj.getProperties());
 }
  • 14. @Test public void testGetImageLegendWithSourceAndCaptionReturnsBoth() throws Exception { ResourceResolver resolver = new ResourceResolverImpl(client); createPage(“/content/foobar”, new Properties(), PageType.PRESENCE.getTemplate()); createPage(“/content/foobar/ko”, new Properties(), PageType.LANGUAGE.getTemplate()); createPage(“/content/foobar/ko/home", new Properties(), PageType.HOME.getTemplate()); createPage(“/content/foobar/ko/home/content", new Properties(), PageType.DETAIL.getTemplate()); Resource contentPage = resolver.getResource(“/content/foobar/ko/home/content"); createResource(contentPage.getPath() + "/jcr:content/textimage", new Properties()); Resource target = resolver.getResource(contentPage.getPath() + "/jcr:content/textimage"); Properties imageProps = new Properties() .append("source", "<sourceValue>") .append("caption", "titleValue") .append("sling:resourceType", ComponentType.IMAGE) .append(JCR_LASTMODIFIED, new Time().format(DateFormat.GMT)) .append(JCR_LAST_MODIFIED_BY, "admin"); createResource(contentPage.getPath() + "/jcr:content/textimage/image", imageProps); TextImageController testObj = new TextImageController().setup(createContext(target, contentPage)); assertEquals("titleValue<br />&lt;sourceValue&gt;", testObj.getImageLegend()); } Key: Test in Isolation.
  • 15. @Test public void testGetImageLegendWithSourceAndCaptionReturnsBoth() throws Exception { ResourceResolver resolver = new ResourceResolverImpl(client); createPage(“/content/foobar”, new Properties(), PageType.PRESENCE.getTemplate()); createPage(“/content/foobar/ko”, new Properties(), PageType.LANGUAGE.getTemplate()); createPage(“/content/foobar/ko/home", new Properties(), PageType.HOME.getTemplate()); createPage(“/content/foobar/ko/home/content", new Properties(), PageType.DETAIL.getTemplate()); Resource contentPage = resolver.getResource(“/content/foobar/ko/home/content"); createResource(contentPage.getPath() + "/jcr:content/textimage", new Properties()); Resource target = resolver.getResource(contentPage.getPath() + "/jcr:content/textimage"); Properties imageProps = new Properties() .append("source", "<sourceValue>") .append("caption", "titleValue") .append("sling:resourceType", ComponentType.IMAGE) .append(JCR_LASTMODIFIED, new Time().format(DateFormat.GMT)) .append(JCR_LAST_MODIFIED_BY, "admin"); createResource(contentPage.getPath() + "/jcr:content/textimage/image", imageProps); TextImageController testObj = new TextImageController().setup(createContext(target, contentPage)); assertEquals("titleValue<br />&lt;sourceValue&gt;", testObj.getImageLegend()); } Arrange Key: Test in Isolation.
  • 16. @Test public void testGetImageLegendWithSourceAndCaptionReturnsBoth() throws Exception { ResourceResolver resolver = new ResourceResolverImpl(client); createPage(“/content/foobar”, new Properties(), PageType.PRESENCE.getTemplate()); createPage(“/content/foobar/ko”, new Properties(), PageType.LANGUAGE.getTemplate()); createPage(“/content/foobar/ko/home", new Properties(), PageType.HOME.getTemplate()); createPage(“/content/foobar/ko/home/content", new Properties(), PageType.DETAIL.getTemplate()); Resource contentPage = resolver.getResource(“/content/foobar/ko/home/content"); createResource(contentPage.getPath() + "/jcr:content/textimage", new Properties()); Resource target = resolver.getResource(contentPage.getPath() + "/jcr:content/textimage"); Properties imageProps = new Properties() .append("source", "<sourceValue>") .append("caption", "titleValue") .append("sling:resourceType", ComponentType.IMAGE) .append(JCR_LASTMODIFIED, new Time().format(DateFormat.GMT)) .append(JCR_LAST_MODIFIED_BY, "admin"); createResource(contentPage.getPath() + "/jcr:content/textimage/image", imageProps); TextImageController testObj = new TextImageController().setup(createContext(target, contentPage)); assertEquals("titleValue<br />&lt;sourceValue&gt;", testObj.getImageLegend()); } Arrange Act Key: Test in Isolation.
  • 17. @Test public void testGetImageLegendWithSourceAndCaptionReturnsBoth() throws Exception { ResourceResolver resolver = new ResourceResolverImpl(client); createPage(“/content/foobar”, new Properties(), PageType.PRESENCE.getTemplate()); createPage(“/content/foobar/ko”, new Properties(), PageType.LANGUAGE.getTemplate()); createPage(“/content/foobar/ko/home", new Properties(), PageType.HOME.getTemplate()); createPage(“/content/foobar/ko/home/content", new Properties(), PageType.DETAIL.getTemplate()); Resource contentPage = resolver.getResource(“/content/foobar/ko/home/content"); createResource(contentPage.getPath() + "/jcr:content/textimage", new Properties()); Resource target = resolver.getResource(contentPage.getPath() + "/jcr:content/textimage"); Properties imageProps = new Properties() .append("source", "<sourceValue>") .append("caption", "titleValue") .append("sling:resourceType", ComponentType.IMAGE) .append(JCR_LASTMODIFIED, new Time().format(DateFormat.GMT)) .append(JCR_LAST_MODIFIED_BY, "admin"); createResource(contentPage.getPath() + "/jcr:content/textimage/image", imageProps); TextImageController testObj = new TextImageController().setup(createContext(target, contentPage)); assertEquals("titleValue<br />&lt;sourceValue&gt;", testObj.getImageLegend()); } Arrange Act Assert Key: Test in Isolation.
  • 18. Dependencies vs. Isolation Sandbox Test Object {state, behavior} Direct Collaborator {state, behavior} Indirect Collaborator {state, behavior} Parent {state, behavior} Data {state} Event {state, behavior}
  • 19. Arrange: Dependencies? • What: State, Behavior[, Event and Data] • Where: Local, Parent, External • How: • Explicit/Implicit: Is it injectable? • Direct/Indirect: Do I depend on it directly? • Accessible/Inaccessible: Is it static, final etc.?
  • 20. Mockito 101 • Mock: Empty Object: No state, No behavior.
 
 ItemService service = mock(ItemService.class); • Stub: Specify Behavior
 
 when(service.load(“index.html”)).thenReturn(“foobar”); • Spy: Real Object: Real / partial state and behavior
 
 ItemService service = spy(new ItemService());
 doReturn(“foobar”).when(service).load(“index.html”);
  • 21. Partial Mocking • Gradually mock behaviour • mock(FooBar.class) • mock(FooBar.class, CALLS_REAL_METHODS) • spy(new FooBar())
  • 22. Default Answers public IProjectLink aProjectLink(String label, String linkType) { IProjectLink result= mock(IProjectLink.class, RETURNS_SMART_NULLS); when(result.getLabel()).thenReturn(label); when(result.getLinkType()).thenReturn(linkType); return result; } • Other default answers: • CALLS_REAL_METHODS (partial mocking) • RETURNS_MOCKS (mock return values) • RETURNS_DEEP_STUBS (stub transitively) • RETURNS_DEFAULTS (default answer)
  • 23. Stub it in or out? when(mock.methodCall(Matcher.anyString())).thenReturn(“value”); when(mock.methodCall(Matcher.anyString())).then(new Answer() {}); when(mock.methodCall(Matcher.anyString())).thenThrow(Exception.class); doReturn(“value”).when(mock).methodCall(Matcher.anyString()); doAnswer(new Answer() {}).when(mock).methodCall(Matcher.anyString()); doThrow(Exception.class).when(mock).methodCall(Matcher.anyString()); obj method argument matchers value / answer obj method argument matchersvalue / answer
  • 24. Danger: Partial Mocks public String load(String path) throws FooException { // ... // method behavior //... return result; } doReturn().when() ——> when().thenReturn() ——> public class DbTest {
 @Mock
 private IPropertiesStore mockedStore;
 @InjectMocks
 private DB testObj;
 @Before
 public void setUp() throws Exception {
 testObj = DB.init();
 MockitoAnnotations.initMocks(this);
 }
 InjectBehavior InjectState
  • 25. Assert: Effects? • Assert genuine effects: • Returned values. Changed state. Exceptions.
 
 assertEquals(), assertNotNull(), @Test(expect = …) • Mocks/spies verify behavior: • Called methods. Count calls. Capture arguments. 
 
 verify(mock,times(2)).methodFoo(Matchers.anyString())
  • 26. Verify: calls w/ args @Test public void getContentShouldManageInputStreamsProperly() throws Exception { InputStream inputStream= spy(new FileInputStream(new File("tmp/test.txt"))); Response testObj= spy(new Response( HttpStatus.SC_OK, Collections.emptyMap(), inputStream)); testObj.getContent(); // way too many examples verify(inputStream, times(2)).close(); verify(inputStream, atMost(2)).close(); verify(inputStream, timeout(100).atLeastOnce()).close(); verify(inputStream, never()).reset(); verify(testObj).getResponseHeader(anyString()); verify(testObj).getResponseHeader(eq(HttpUtil.CONTENT_TYPE)); }
  • 27. Matchers make it fit ๏ org.mockito.Matchers, e.g.: • any(Class<T>), anyBoolean() • isA(Class<T>), eq(T), refEq(T, String…) • isNull(Class<T>), notNull() • same(T), contains(String) • matches(String) ๏ Use org.hamcrest.Matchers with, e.g.: • argThat(Matcher<T>) • charThat(Matcher<Char>), • booleanThat(Matcher<Boolean>)
  • 29. Add unit tests createItem(Item) : Item getItem(String) : Item updateItem(Item) : Item ItemService + init() : DB + get(String) : Item + store(Item) : DB + delete(String) : DB + exists(Item) : boolean - singleton : DB DB + load(String) : Properties + save(String, Properties) : IPropertiesStore + remove(String) : IPropertiesStore IPropertiesStore + load(String) : Properties + save(String, Properties) : IPropertiesStore + remove(String) : IPropertiesStore - data : Map<String, Properties> InMemoryPropertiesStore datastorage + getPath() : String + getProperties() : Properties + setProperties(Properties) : Item - path : String Item + hasProperty(Object) : boolean +setValue(Object, Object) : Properties + getValue(Object key) : Object - data : Map<Object, Object> Properties properties
  • 30. Get the Code. https://github.com/jwloka/mocktesting/ git clone ssh://git@github.com/jwloka/mocktesting.git Run it. $ mvn clean install
  • 31. Write valuable tests. • Go through the code add unit tests • Think about what to mock and why? • Where to start? Follow the hints in the code! • Remember: You are allowed to change the code!
  • 32. Get the solution. git checkout tags/v2
  • 33. Mocks, revisited • Can Mocking cause poorly factored code? • Need for mocks: design feedback • Be aware deeply nested mocks! • Can Mocking break encapsulation? • Mocked internal state • Need for behavior verification • Can Mocking create artificial behavior? • Mocks with state are dangerous • Use stubs with canned values • Can Mocking reduce test value? • Mock direct collaborators only • Under-specify with matchers
  • 34. No Hangover, please! Rules of the road: • Try to use the real thing • Mocks are for direct collaborators • Never mock the test object • Be aware of deeply-nested mocks, e.g. RETURN_DEEP_STUBS • Stateless mocks, with stubs to return canned values • Don’t verify on non public API • Under-specify in mocks and stubs with matchers.
  • 35. Ready. Set. Go. • Unit Testing In The Real World • More guidance. More examples. • How to write unit tests? • Measure test coverage.