47
Functional Scala Testing: LambdaTest John Nestor 47 Degrees www.47deg.com https://github.com/47deg/LambdaTest December 13, 2016 1 47deg.com

LambdaTest

Embed Size (px)

Citation preview

Functional Scala Testing:LambdaTest

John Nestor 47 Degrees

www.47deg.com

https://github.com/47deg/LambdaTest

December 13, 2016

147deg.com

47deg.com © Copyright 2016 47 Degrees

Outline

• Introduction

• Concepts

• Exceptions

• Immutable and Mutable

• ScalaCheck

• Options

• Tags

• Timing

• Running

• Extending

• Coming Soon: Asynchronous testing

2

Introduction

3

47deg.com © Copyright 2016 47 Degrees

My Testing Philosophy

• Not a big system that tries to provide everything for everybody

• Instead a small clean system that is easy to extend and tailor from small simple customization through major custom testing systems

• Testing for developers not managers

• Test code should be high leverage

• Testing is programming not a list of specific simple tests

• Scala and functional programming is my focus

4

47deg.com © Copyright 2016 47 Degrees

Existing Scala Scala Test Frameworks

• Java testing (JUnit)

• ScalaTest (400K lines)

• Specs2 (50K lines)

• UTest (< 1K lines, supports ScalaJS)

• ScalaCheck (property based testing)

5

47deg.com © Copyright 2016 47 Degrees

Goals of New Scala Testing Framework

• Designed for developers not managers or PM’s

• Pure Scala. (No Java code)

• Purely functional (no mutable state)

• Small, simple, clean (~1K lines of Scala code)

• Easy to extend and customize

• Supports ScalaCheck

6

47deg.com © Copyright 2016 47 Degrees

A Simple Example

• “com.fortyseven” % “lambda-test” % “1.1.2” % “test”

• import com.fortysevendeg.lambdatest._

• class Example extends LambdaTest { val act = … }

• Quickly show and run demo Example.scala. We will come back to it later to explain in detail how it works. For now, get a general feel.

7

Concepts

8

47deg.com © Copyright 2016 47 Degrees

OO Versus Functional

• OO. Object contains mutable state. Operations change that state.

• Functional. Object contains only immutable state. Operations produce a new immutable state object.

9

47deg.com © Copyright 2016 47 Degrees

Major Types

• States. An immutable value that represents each state during testing. Type LambdaState. There is an initial state before all tests and a final state after all tests are run.

• Transformations. A function that maps an old state to a new state. Type LambdaState => LambdaState.

• Actions. A sequence of zero or more transformations. Type LambdaAct. In simple case contains exactly one transform. Can be combined using infix +.

• Reporters. A way to report test results. Type LambdaReporter. Each state has a reporter. Reporter state is also immutable (but may have output side effects, see later).

• Options. Type LambdaOptions. Each state has its own options. Options are also immutable.

10

47deg.com © Copyright 2016 47 Degrees

Overall State Transitions

11

S0 S1 S2 S3 S4 S5

S0 S1 S2 S3 S4 S5

Incremental Output

Held Output

47deg.com © Copyright 2016 47 Degrees

Major Kinds of Actions

• Primitive actions

• Assertions: assert assertEq assertEx assertSC

• Exec: exec

• Compound actions (contain other actions)

• Test: test

• Other: label, nest

• Timing: timer, assertTime, assertPerf

• User defined: wrappers, …

12

47deg.com © Copyright 2016 47 Degrees

Actions State Transitions

13

S1 S2

S1 S2

SA SB SC

Primitive Action

Compound Action

S1

47deg.com © Copyright 2016 47 Degrees

Revisit Example

• Examine and run Example.scala. Now with more knowledge of how it works.

14

Exceptions

15

47deg.com © Copyright 2016 47 Degrees

Handling Exceptions

• Expected exception. Use assertEx action. Flexible check option.

• Unexpected exception. Testing system, detects, reports and when possible recovers from unexpected exceptions and errors (for example ???).

16

47deg.com © Copyright 2016 47 Degrees

Exception Example

• Examine and run Except.scala

17

Immutable and Mutable

18

47deg.com © Copyright 2016 47 Degrees

Immutable and Mutable

• LambdaCheck is itself functional/immutable

• It is ideal for testing functional/immutable code.

• But it can also be used to test code that is mutable.

19

47deg.com © Copyright 2016 47 Degrees

Putting Code Around a Sequence of Assertions

• Before all. In the body of a test or label. Can contain declarations visible in assertions.

• Between (mutable). Use an exec action. Can modify the state of declarations from before.

• Between (immutable). Use nesting.

• After all. User defined wrappers (more on this later).

20

47deg.com © Copyright 2016 47 Degrees

Mutable and Immutable Code Examples

• Examine and run demo Mutable.scala.

• Examine and run demo Immutable.scala

21

47deg.com © Copyright 2016 47 Degrees

Wrappers

• Replace the Before and After features of ScalaTest and Specs2.

• Purely functional/immutable. No need for the global mutable state needed in ScalaTest and Specs2.

• A wrapper is a user defined compound action.

• Wrappers can catch exceptions (for cleanup) and can hide some of its enclosing state from the assertions it wraps.

22

47deg.com © Copyright 2016 47 Degrees

Wrapper Example

• Makes use of the eval operation on its body (of type LambdaAct).

• Examine and run Wrap.scala.

23

ScalaCheck

24

47deg.com © Copyright 2016 47 Degrees

ScalaCheck Concepts

• Generators (generate a set of values)

• Random

• Specified

• Combined

• Properties (test an assertion on a set of values)

• forAll

• exists

• http://noelmarkham.github.io/practical-scalacheck/index.html#/

25

47deg.com © Copyright 2016 47 Degrees

ScalaCheck Example

• Wrap in action assertSC

• Examine and run demo ScalaCheck.scala

26

Options

27

47deg.com © Copyright 2016 47 Degrees

Options

• Default state: look at reference.conf

• Options can be overriden for any action.

• Look at and run Off demo

28

Tags

29

47deg.com © Copyright 2016 47 Degrees

Tags

• Tags enable the selection of subsets of actions to be run

• Can be specified on label and test actions

• Are controlled by options

• Look at and run Tag demo

30

Timing

31

47deg.com © Copyright 2016 47 Degrees

Timing

• timer: times a block of code

• assertTime: checks that code is fast enough

• assertPerf: runs code multiple times and reports mean, max and standard deviation. Can set limits on mean and max

• Look at and run Timing demo

32

Running

33

47deg.com © Copyright 2016 47 Degrees

Running

• Directly. Companion object with main method calls run function

• Uses the StdoutLambdaReporter

• SBT. Can use any of the SBT test commands.

• Uses the SbtLambdaReporter

34

47deg.com © Copyright 2016 47 Degrees

Reporters and Side-Effects

• A pure functional program should not have side effects.

• It is possible to defer all the report output side effects until after a purely functional testing core.

• But it is often nice to see report output incrementally as it is produced. So we sacrifice a little purity for convenience.

• There is however another special purely-functional side-effect-free reporter: HoldLambdaReporter. We will see a couple of its uses later in the talk.

35

47deg.com © Copyright 2016 47 Degrees

Parallel Execution

• By default, tests are run and reported serially in the order written.

• The run function, label action and test action support an optional parallel parameter.

• Parallel actions are run on separate Scala futures but with the results still being reported in order written.

• To prevent mixing of output from different actions, all but the first are run using the hold reporter.

• Parallel logic is contained inside the eval method of LambdaAct.

36

47deg.com © Copyright 2016 47 Degrees

Options

• Testing options are specified using Typesafe config.

• Examine reference.conf

• Change via API

37

Extending

38

47deg.com © Copyright 2016 47 Degrees

Kinds of Extensions

• Generating actions

• Defining new actions

39

47deg.com © Copyright 2016 47 Degrees

Generating Actions

• Implicit conversion Seq[LambdaAct] => LambdaAct

• Examine and run generate.scala

40

47deg.com © Copyright 2016 47 Degrees

Layer Diagram

41

LambdaStateLambdaAct

+ Actions

User Tests

Testing Core

eval LambdaState API

47deg.com © Copyright 2016 47 Degrees

Defining new Actions

• API to change state. Should not be called directly in user test code. Only used for extensions.

• LambdaAct eval changes state

• LambdaState method

• Examine ScalaDoc

• Examples

• Wrappers

• Examine predefined actions in lambdatest package object.

42

Coming Soon

43

47deg.com © Copyright 2016 47 Degrees

Coming Soon: LambdaTestExpect

• Test that something that is expected happens

• Handles asynchronous actions

• Testing

• Futures

• Actor messages

• Akka events

• Log messages

• …

44

47deg.com © Copyright 2016 47 Degrees

Expect

• Extends LambdaTest (no modifications needed!)

• It can itself be customized/extended

• Uses Akka Actors

• Two modes

• Poll: Expect a condition to become true

• Subscribe: Expect an event or pattern of events

• In either case there is a timeout

45

47deg.com © Copyright 2016 47 Degrees

Expect

• Polling demo

• Log demo

• Actor demo

46

Questions

47