Slide 1

Slide 1 text

Unit Testing with RUnit using RUnit, R Studio, & Git

Slide 2

Slide 2 text

Context ● check units of source code ● write the test, then the function (TDD) ● kata learned by repeated execution ● red, green, refactor ● “just enough” code to go green

Slide 3

Slide 3 text

History 1960 - Test-case library (punch cards/fortran) 1994 - SUnit (Smalltalk) 1998 - JUnit (Java) 2000 - NUnit (.Net) 2008? - RUnit (R)

Slide 4

Slide 4 text

Flavors ● svUnit ● Testthat ● RUnit

Slide 5

Slide 5 text

Flavors ● svUnit ● Testthat ● RUnit - most similar to unit testing for other languages

Slide 6

Slide 6 text

RUnit Components ● RUnit Package ● run_tests.R file ● tests directory ● test file ● code file

Slide 7

Slide 7 text

RUnit Tests “checkFuncs” TEST SYNTAX testName <- function() { checkFuncs(a, b) } CHECK FUNCTIONS ● checkEquals ● checkEqualsNumeric ● checkException ● checkIdentical ● checkTrue

Slide 8

Slide 8 text

TDD Basic Concepts Unit Tests guide step-by-step success ● function exists? ● call returns a value? ● value matches expectation?

Slide 9

Slide 9 text

Example - convert ℃ to ℉ f = 9/5c + 32 DON’T WRITE THE FUNCTION!

Slide 10

Slide 10 text

Test Controller - run_tests.R # run_tests library('RUnit') testsuite.c2f <- defineTestSuite( name = "c2f", dirs = file.path("tests"), testFileRegexp = "^runit.+\\.[rR]$", testFuncRegexp = "^test.+", rngKind = "Mersenne-Twister", rngNormalKind = "Inversion" ) source('c2f.R') testResult <- runTestSuite(testsuite.c2f) printTextProtocol(testResult)

Slide 11

Slide 11 text

Test Controller - run_tests.R # run_tests library('RUnit') testsuite.c2f <- defineTestSuite( name = "c2f", dirs = file.path("tests"), testFileRegexp = "^runit.+\\.[rR]$", testFuncRegexp = "^test.+", rngKind = "Mersenne-Twister", rngNormalKind = "Inversion" ) source('c2f.R') testResult <- runTestSuite(testsuite.c2f) printTextProtocol(testResult)

Slide 12

Slide 12 text

Test Controller - run_tests.R # run_tests library('RUnit') testsuite.c2f <- defineTestSuite( name = "c2f", dirs = file.path("tests"), testFileRegexp = "^runit.+\\.[rR]$", testFuncRegexp = "^test.+", rngKind = "Mersenne-Twister", rngNormalKind = "Inversion" ) source('c2f.R') testResult <- runTestSuite(testsuite.c2f) printTextProtocol(testResult)

Slide 13

Slide 13 text

Test Controller - run_tests.R # run_tests library('RUnit') testsuite.c2f <- defineTestSuite( name = "c2f", dirs = file.path("tests"), testFileRegexp = "^runit.+\\.[rR]$", testFuncRegexp = "^test.+", rngKind = "Mersenne-Twister", rngNormalKind = "Inversion" ) source('c2f.R') testResult <- runTestSuite(testsuite.c2f) printTextProtocol(testResult)

Slide 14

Slide 14 text

Test Controller - run_tests.R # run_tests library('RUnit') testsuite.c2f <- defineTestSuite( name = "c2f", dirs = file.path("tests"), testFileRegexp = "^runit.+\\.[rR]$", testFuncRegexp = "^test.+", rngKind = "Mersenne-Twister", rngNormalKind = "Inversion" ) source('c2f.R') testResult <- runTestSuite(testsuite.c2f) printTextProtocol(testResult)

Slide 15

Slide 15 text

Test Controller - run_tests.R # run_tests library('RUnit') testsuite.c2f <- defineTestSuite( name = "c2f", dirs = file.path("tests"), testFileRegexp = "^runit.+\\.[rR]$", testFuncRegexp = "^test.+", rngKind = "Mersenne-Twister", rngNormalKind = "Inversion" ) source('c2f.R') testResult <- runTestSuite(testsuite.c2f) printTextProtocol(testResult)

Slide 16

Slide 16 text

Test Controller - run_tests.R # run_tests library('RUnit') testsuite.c2f <- defineTestSuite( name = "c2f", dirs = file.path("tests"), testFileRegexp = "^runit.+\\.[rR]$", testFuncRegexp = "^test.+", rngKind = "Mersenne-Twister", rngNormalKind = "Inversion" ) source('c2f.R') testResult <- runTestSuite(testsuite.c2f) printTextProtocol(testResult)

Slide 17

Slide 17 text

Test Controller - run_tests.R # run_tests library('RUnit') testsuite.c2f <- defineTestSuite( name = "c2f", dirs = file.path("tests"), testFileRegexp = "^runit.+\\.[rR]$", testFuncRegexp = "^test.+", rngKind = "Mersenne-Twister", rngNormalKind = "Inversion" ) source('c2f.R') testResult <- runTestSuite(testsuite.c2f) printTextProtocol(testResult)

Slide 18

Slide 18 text

With R Studio that looks like... c2f ├── README.md ├── c2f.Rproj ├── c2f.R ├── run_tests.R └── tests └── runitc2f.R

Slide 19

Slide 19 text

TDD: Red, Green, Refactor Red - Write a test that will fail Green - Write code to make the test pass Refactor - Clean up

Slide 20

Slide 20 text

Version COntrol with Git? Initial commit - required components Branch - new branch for each test Merge - When test works, merge to master Why? - Master always works branches are a history of progress

Slide 21

Slide 21 text

Example - convert ℃ to ℉ f = 9/5c + 32 DON’T WRITE THE FUNCTION!

Slide 22

Slide 22 text

First Test - The Simplest Thing... TEST FILE testZeroC <- function() { fTemp <- c2f(0) } RED - because there isn’t any such function FUNCTION FILE

Slide 23

Slide 23 text

First Test - The Simplest Thing... TEST FILE testZeroC <- function() { fTemp <- c2f(0) } GREEN - but no test! FUNCTION FILE c2f <- function(c) { return(0) }

Slide 24

Slide 24 text

First Test - The Simplest Thing... TEST FILE testZeroC <- function() { fTemp <- c2f(0) checkEquals(32, fTemp) } RED - 32 ≠ 0 FUNCTION FILE c2f <- function(c) { return(0) }

Slide 25

Slide 25 text

First Test - The Simplest Thing... TEST FILE testZeroC <- function() { fTemp <- c2f(0) checkEquals(32, fTemp) } Green - 32 = 32 FUNCTION FILE c2f <- function(c) { return(32) }

Slide 26

Slide 26 text

First Test - The Simplest Thing... TEST FILE testZeroC <- function() { fTemp <- c2f(0) checkEquals(32, fTemp) } Refactor - Don’t need fTemp FUNCTION FILE c2f <- function(c) { return(32) }

Slide 27

Slide 27 text

First Test - The Simplest Thing... TEST FILE testZeroC <- function() { checkEquals(32, c2f(0)) } FUNCTION FILE c2f <- function(c) { return(32) }

Slide 28

Slide 28 text

Second Test - More than one temp TEST FILE testZeroC <- function() { checkEquals(32, c2f(0))} test35C <- function() { checkEquals(95, c2f(35))} Red - 32 ≠ 95 FUNCTION FILE c2f <- function(c) { return(32) }

Slide 29

Slide 29 text

Second Test - More than one temp TEST FILE testZeroC <- function() { checkEquals(32, c2f(0))} test35C <- function() { checkEquals(95, c2f(35))} Green- 32 = 32 & 95 = 95 FUNCTION FILE c2f <- function(c) { return(9/5 * c + 32) }

Slide 30

Slide 30 text

Second Test - More than one temp TEST FILE testZeroC <- function() { checkEquals(32, c2f(0))} test35C <- function() { checkEquals(95, c2f(35))} Refactor? FUNCTION FILE c2f <- function(c) { return(9/5 * c + 32) }

Slide 31

Slide 31 text

Third Test - Exceptions? TEST FILE testZeroC <- function() { checkEquals(32, c2f(0))} test35C <- function() { checkEquals(95, c2f(35))} testStringC <- function() { checkException(c2f('x'))} FUNCTION FILE c2f <- function(c) { return(9/5 * c + 32) }

Slide 32

Slide 32 text

References RUnit: http://cran.r-project.org/web/packages/RUnit/index.html http://cran.r-project.org/web/packages/RUnit/RUnit.pdf http://cran.r-project.org/web/packages/RUnit/vignettes/RUnit.pdf http://master.bioconductor.org/developers/how-to/unitTesting-guidelines/ Katas with TDD: https://vimeo.com/43734265 http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata http://www.peterprovost.org/blog/2012/05/02/kata-the-only-way-to-learn-tdd/ History of Unit Testing: http://c2.com/cgi/wiki?TenYearsOfTestDrivenDevelopment http://shebanator.com/2007/08/21/a-brief-history-of-test-frameworks/ http://history.nasa.gov/computers/Ch8-2.html

Slide 33

Slide 33 text

No content