Testing Practicies not only in Scala

by Paweł Panasewicz

pawel.panasewicz(at)gmail.com

@pawelpanasewicz

github.com/PawelPanasewicz

... actually ...

ScaLAB Conference, 2016 Wrocław

Who am I

  • Professionally for > 10 years in Software Development
    • mostly in commercial projects
  • Impressed by Scala Language and Functional Approach
  • In free time
    • engaged in Music Production
    • learning about Artificial Intelligence
    • like to ride bicycle

Prologue

The Analyst

                            val analyst =                            //there was an analyst
                              Analyst(whatLearnt = Set())            //at the beginning he knew not a lot
                              .copy(whatLearnt = Set(UML, SQL, XML)) //but in time he's achieved skills
                            
                            analyst
                              .changeYear(_ + 5)                     //... few years later
                              .`are my skills still up to date`      //?
                                                                     //👍 All Skills Up To Date

The Project Manager

                            val manager =                            //there was a project manager
                              ProjectManager(whatLearnt = Set())     //at the beginning he knew not a lot
                               .copy(whatLearnt = Set(GantChart,
                                  ManagingStyles.visionary, WritingSolemnEmails,
                                  ManagingStyles.commanding)
                              )                                      //but in time he's achieved skills
                            
                            manager
                              .changeYear(_ + 5)                     //... few years later
                              .`are my skills still up to date`      //?
                                                                     //👍 All Skills Up To Date

The Software Developer

                            val developer =                        //there was a software developer
                              Developer(whatLearnt = Set())        //at the beginning he knew not a lot
                                .copy(whatLearnt = Set(
                                  Slick1, Slick2, Spray1, Angular1, play1,
                                  `play < 2.5`, `your favourite example of not to old tech`
                                ))                                //intelligent beast has learnt a lot
                            
                            developer
                              .changeYear(_ + 5)                  //... few years later
                              .`are my skills still up to date`   //?
                                                          // 😕 Well Not Really

So what?

  • The best-before date of IT technologies are often short space of time
  • As good Software Developer you have to frequently update your skills
  • It would be nice if there were some areas which don't change so rapidly
  • because you could successfully take advantages of them for long time
  • Well, there are such areas and among them:

Agenda

  • Why to test code?
  • What  code testing is all about?
  • Good practicies

in order to deliver high quality sofware and be safe

In general

Why

to test code?

Why

In particular

to test code?

  • to demonstrate that the software satisfies its specification
  • to find bugs during development phase, not during production run
  • to be safe when refactoring - tests will notify me when introducing regression errors

 

  • I want to show the estimation of work done - there is as much progress as many test scenarios in code base
  • I want to document how my codes and whole system works - it's helpfull not only for other devs but as well managers, analysts and users.
  • TDD techniques guide mu during development
  • ATDD techniques make sure system does what business/users/analysts needs
  • I want to report performance of my application
  • I want to repair system because of the bug on production - first I develop the failing test which reprodces the error, next I can fix it
  • I am just a prone to make mistakes human
  • many other factors inlcuding ~120 Mega results from google.com:

 

In particular

Why

to test code?

What

is code testing all about?

Code testing is all about writing another code which will satisfy needs mentioned in the "Why" section

In general

In particular

Piece of code

definition

Unit & Integration tests

what are?

code code code code code ... code code code code code

these kind of codes are tested by integration tests

these kind of codes are tested by unit tests

one big integrated code

perfect undivided unit of code

E2E, System Tests

Acceptance, Functional, UI

API Tests

Component,

Isolated UI,

Just Unit Test

 

- tests are performed when application is deployed on environment

- tests are performed during builds and development

  • they test if many components cooperate well together
  • by developers not only to developers
  • slower
  • they test behaviour of relative small pieces of code in isolation
  • by developers to developers
  • easy to test many scenarios and hunt a bug
  • fast
  • mocking

 

Acceptance/Functinal tests

Unit tests

Unit vs Functional

tests

  • ensure that app works according to business requirements (whatever the implementation is)
  • do assure that developer's design is in accordance with business requirements
  • functionality guards
  • more parts together then less worries
  • ensure that piece of code works according to developer's design

  • do not assure that developer's design is in accordance with business requirements

  • it's often silently assumed that mocked dependecies  will behave in particular way which is dangerous 'cuz unit tests will not cover that

when designing new functionality

Unit vs Functional

Acceptance/Functinal tests

Unit tests

Plan of attack

when delivering new functionality

  1. Start from basic acceptance tests
  2. Keep on refactoring
  3. When requirements and architecture stops evolving hunt for bugs using extensive Unit Tests

Good Practicies

advices when testing

  • Develop Calendar Service
  • CS must decide if particular day is a working day or a holiday
  • API exposed in rest-like form

The Calendar Service

Example

BTW There are two devs delegeted to this task

Let's assume that we are using ScalaTest , and somehow there are imported testing goodies like HttpClient and nextFreePort() ...

First

Hmm, a little bit red, let's create the simplest implementation

small happy path acceptance scenario

Test Run

failed red

Implementation

as simple as needed

  • keybord is swapped and second developer is making implementation whereas the first one is observing
  • (no slide with code with correct implementation, sorry for that)

green

Test re-run

once again

great success !

Mondays are working days

more happy paths

  • keybord is swapped, the second dev is observing now
  • new testcases (still happy paths) are made

red

Test re-run

once again

Implementation

without extra features

  • keybord is swapped and second developer is making implementation whereas the first one is observing
  • (no slide with code with correct implementation, sorry for that)

red

Test re-run

and regression error found

  • ooopps, something went wrong ...
  • REGRESSION ERROR introduced
  • Tests are for rescue 😎

Implementation

and debugging

  • keybord is swapped and second developer is making implementation whereas the first one is observing

red

Test re-run

all green

Refactoring

optimise readability, make it beautiful

"table of contents"

private guts in descendent order of importance

red

Test re-run

all green

Quiz

Which "design patterns" have you noticed here?

  • Make it testable - the most important
  • TDD (or even ATDD or BDD)
  • Red Green Refactor
  • Happy Path first
  • Important goes up
  • Pair Programming
  • Baby steps
  • almost like a "pure function"
  • KISS

The Calendar Service

new requirements

  • different clients of CS have different working days
  • default functionality must be preserved

Meet the Table

and put test cases in such form

  • easy to create new test cases
  • easy to read

"Table of contents"

still in front of spec

and test routine may look like this:

Quiz

Which new "design patterns" have you noticed here?

  • Table Driven Testing

The Calendar Service

new requirements

  • it must be documented
  • documentation must be always up to date

Documenting 

the functionality

Under the hood

it's just simple HTML

  • extra html attributes
  • part of resources

Executing Spec

is performed during tests

  • Html document can be parsed
  • Extra HTML attribues can help in that
  • Extracted values can be seen as:
  • and can be used to generate many testcases
  • which can be used for testing

Spec output

after test run

  • green - tests succeded
  • red - tests failed

Quiz

Which new "design patterns" have you noticed here?

  • Executable Spec (Living Documentation)

Living Documentation

closer look at

  • Engage [developers] with your users
  • Create a shared domain language
  • Build mutually-understood delivery contracts
  • Describe the system concisely, so that errors and redundancy are easily visible
  • Write living documentation: always coupled to the actual behaviour of the system

 - Chris Agmen Smith - autor of Petswood

The Calendar Service

new requirements

  • web page

Project of web page

functionality

Choose system, provide date string, click submit. There should appear message "working day" or "holiday" i n gray area. (sorry for typos)

Test routine

could look like this

it's ugly, unreadable

Abstract 

over it 

  • create high level API for manipulating the page
  • API can contain assertions (checkThatContains)
  • API can be reused
  • nicely explains what the test does

Quiz

Which  design pattern have you noticed here?

Other techniques

handy when testing

Bob Snaphot's

technique

  •  record input and output and use this data for testing
  •  if actual output during tests differs from recorded that means that regression errors were introduced
  • save output to files when test run and use diff tool for fast spot differences
  •  use it 
    •  when you don't really know what right behaviour/ouptut should be
    •  only subject expert matter can decide if behaviour is fine
    •  when you render something

 

More test code lines

then production code lines

  • It's good sign
  • measure it

howitworks

package

  • use it as playground when learning something new which might be used in project
  • easy to copy/paste working solution 
  • easy to remove when not needed or disturbing
  • often better then stackoverflow

Domain Test Data in one place

good practice

  •  test data builders and factories
  •  example data in one place
  •  even identifiers of rows id DB and their values
  •  understanding domain data is key to understand what system is supposed to do

That's it

Thank you!

Questions?