unit/integration testing using spock

Post on 14-Jan-2017

100 Views

Category:

Technology

6 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Unit Testing using SpockPresented By: Anuj Aneja

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.

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.

Do we need to test the code before we build it?

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.

Unit testing using Spock

What is Spock? Why Spock? Example Test Structure Creating Mock Checking interactions with Mock object Matching invocations in mocks

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

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.

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.

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

Output: Error Message

Condition not satisfied: 2 == list.get(0)  |  |    |  |  [1]  1  false

Test Structure

Each test can be divided into three sections Given When Then

Alternative Sections: Setup expect

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(user, page) then: // expect specific result authorized == false}

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

Flow

Creating MockIn 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) }

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

OutputError Message:

Too few invocations for: 1 * list.size()   (0 invocations) Unmatched invocations (ordered by similarity): None

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)

Check the order of executionWhat 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()}

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

Managing exceptions in testsThere are special method for handling exception checkingThrown(), 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?"}

Shared variablesIf 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.

@Sharedprivate List<Integer> list = []

def "test 1"() { when: list.add(1) then: list.size() == 1}

def "test 2"() { when: list.add(1) then: list.size() == 2}

“>>” operator & stubbingStubbing 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"

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

Good practicies:

Using descriptive methods inside test Removing disruptive code

Removing disruptive codeprivate User userprivate Action actionprivate 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)}

Q & A

top related