2. What is unit testing?
A unit is the smallest testable part of an application like
functions, classes, procedures, interfaces. Unit testing is
a method by which individual units of source code are
tested to determine if they are fit for use.
Unit tests are basically written and executed by software
developers to make sure that code meets its design and
requirements and behaves as expected
The goal of unit testing is to segregate each part of the
program and test that the individual parts are working
correctly.
This means that for any function or procedure when a
set of inputs are given then it should return the proper
values. It should handle the failures gracefully during
the course of execution when any invalid input is given.
3. What is unit testing?…..continued
A unit test provides a written contract that the piece of
code must assure. Hence it has several benefits.
Unit testing is usually done before integration testing.
4. Do we need to test the code
before we build it?
5.
6. Advantages of Unit Testing
Issues are found at early stage. Since unit testing are
carried out by developers where they test their
individual code before the integration.
Unit testing helps in maintaining and changing the code.
This is possible by making the codes less interdependent
so that unit testing can be executed.
Unit testing helps in simplifying the debugging process.
If suppose a test fails then only latest changes made in
code needs to be debugged.
7. Unit testing using Spock
What is Spock?
Why Spock?
Example
Test Structure
Creating Mock
Checking interactions with Mock object
Matching invocations in mocks
8. Unit testing using spock
Check the order of execution
Specifying a cardinality of an interaction &
wildcards
Managing exceptions in tests
Shared variables
“>>” operator & Stubbing
Good practices
9. What is Spock?
Spock is a unit testing framework that in great extent
utilizes Groovy’s syntax making your tests
comprehensible and easy on the eyes. Although it is a
Groovy technology you can use it to test your Java
classes as well. What is the most important is
that Spock makes writing tests fun. And I really
mean it.
10. Why Spock?
Creating a test in Spock takes less time than using its
standard equivalent (combination of JUnit and some
mocking framework)
Thanks to Groovy’s syntax you can improve tests
clarity even further using closures and straightforward
map ulization.
11. Example
def "should return 2 from first element of list"() {
given:
List<Integer> list = new ArrayList<>()
when:
list.add(1)
then:
2 == list.get(0)
}
13. Test Structure
Each test can be divided into three sections
Given
When
Then
Alternative Sections:
Setup
expect
14. Mandatory Sections Example
def "should return false if user does not have
role required for viewing page"() {
given:
// context within which you want to test the
functionality.
pageRequiresRole Role.ADMIN
userHasRole Role.USER
when:
// some action is performed i.e. actual
method call
boolean authorized =
authorizationService.isUserAuthorizedForPage(u
ser, page)
then:
// expect specific result
authorized == false
}
15. Alternative Sections:
setup,expect
An expect block is more limited than a then block in that
it may only contain conditions and variable definitions. It
is useful in situations where it is more natural to
describe stimulus and expected response in a single
expression. For example, compare the following two
attempts to describe the Math.max() method:
when: def x = Math.max(1, 2)
then: x == 2
expect: Math.max(1, 2) == 2
17. Creating Mock
In order to create a Mock one has to call Mock() method
inside a Spock test.
e.g.
def "creating example mocks"() {
given:
List list = Mock(List)
List list2 = Mock() // preffered way
def list3 = Mock(List)
}
18. Checking interactions with
Mock object
Now that we have created a Mock object, we can check
what has happened with the object during the execution of
code inside when section.
def "size method should be executed one time"() {
given:
List list
when:
list = Mock()
then:
1 * list.size()
}
19. Output
Error Message:
Too few invocations for:
1 * list.size() (0 invocations)
Unmatched invocations (ordered by similarity):
None
20. Matching invocations in
mocks
def "should fail due to wrong user"() {
given:
UserService userService = Mock()
User user = new User(name: 'Mefisto')
when:
userService.save(user)
then:
1 * userService.save({ User u -> u.name == 'Lucas' })
}
Too few invocations for:
1 * userService.save({ User u -> u.name == 'Lucas' }) (0
invocations)
21. Check the order of execution
What is more you can even specify the order by which
interactions should take place. This is achieved by
creating numerous thensections.
def "should first save object before committing
transaction"() {
given:
UserService service = Mock()
Transaction transaction = Mock()
when:
service.save(new User())
transaction.commit()
then:
1 * service.save(_ as User)
then:
1 * transaction.commit()
}
22. Specifying a cardinality of an
interaction & wildcards
then:
// should not be invoked at all
0 * list.size()
// should be invoked at least one time
(1.._) * list.size()
// should be invoked at most one time
(_..1) * list.size()
// any number of calls
_ * list.size()
23. Managing exceptions in tests
There are special method for handling exception
checking
Thrown(), notThrown(), noExceptionThrown()
e.g.
def "should throw IllegalArgumentException with
proper message"() {
when:
throw new IllegalArgumentException("Does
description matter?")
then:
def e = thrown(IllegalArgumentException)
e.message == "Does description matter?"
}
24. Shared variables
If for some reason you would prefer to share the
state of objects created at the level class you
can annotate this particular variable
with @Shared annotation.
@Shared
private List<Integer> list = []
def "test 1"() {
when:
list.add(1)
then:
list.size() == 1
}
def "test 2"() {
when:
list.add(1)
25. “>>” operator & stubbing
Stubbing is the act of making collaborators respond to method calls
in a certain way. When stubbing a method, you don’t care if and
how many times the method is going to be called; you just want it
to return some value, or perform some side effect, whenever it gets
called.
For Example:
interface Subscriber {
String receive(String message)
}
Now, let’s make the receive method return "ok" on every
invocation:
subscriber.receive(_) >> "ok"
26. "Whenever the subscriber receives a message, make it respond with
'ok'."
Compared to a mocked interaction, a stubbed interaction has no
cardinality on the left end, but adds a response generator on the
right end:
subscriber.receive(_) >> "ok"
| | | |
| | | response generator
| | argument constraint
| method constraint
target constraint
28. Removing disruptive code
private User user
private Action action
private TicketOrder order
private BookingService objectUnderTest = new
BookingService()
def "should throw exception if user tries to cancel tickets to
a gig that starts in less than two days"() {
given:
userHasRoleUser()
cancelActionOn10thOfDec2000()
showIsGigThatStartsOn11thOfDec2000()
when:
objectUnderTest.book(user, order, action)
then:
thrown(IllegalActionException)
}