SlideShare una empresa de Scribd logo
Testeo y depuración en R
Primera línea de defensa contra los bugs
Virginia Peón García
Pixabay
Nunca me encontrarán
escondido en el código,
Muahahaha
● Depurando (print)
Temario
● Comprobación de inputs de una función (if / stop / assert)
● Manejando excepciones (try / try catch)
● Test unitarios
○ Características y ejemplos
○ Metodología TDD
Presentación a través de retos
En la exposición voy a ir presentando retos que resolver.
Cuando se alcance el resultado saldrá:
Primer reto
Crear una función, my_factorial(), que calcule el factorial de un
número.
El factorial de un entero positivo n se define como el producto de
los números enteros positivos desde 1 hasta n. Por ejemplo,
El factorial de 5 es:
1*2*3*4*5 = 120
Primera versión
my_factorial <- function(n) {
factorial <- 0
for(i in 1:n) {
factorial <- i * factorial
}
return(factorial)
}
> my_factorial(5)
[1] 0
✗
Depurando con print
my_factorial <- function(n) {
factorial <- 0
for(i in 1:n) {
factorial <- i * factorial
}
return(factorial)
}
> my_factorial(5)
[1] "1 = > 0"
[1] "2 = > 0"
[1] "3 = > 0"
[1] "4 = > 0"
[1] "5 = > 0"
[1] 0
print(paste(i, factorial, sep = " => "))
✗
Depurando con print
my_factorial <- function(n) {
factorial <- 0
for(i in 1:n) {
factorial <- i * factorial
print(paste(i, factorial, sep = " => "))
}
return(factorial)
}
factorial <- 1
✓
> my_factorial(5)
[1] "1 = > 1"
[1] "2 = > 2"
[1] "3 = > 6"
[1] "4 = > 24"
[1] "5 = > 120"
[1] 120
Version depurada
my_factorial <- function(n) {
factorial <- 1
for(i in 1:n) {
factorial <- i * factorial
}
return(factorial)
}
> my_factorial(5)
[1] 120
✓
Comprobación de inputs
> my_factorial(5)
[1] 120
> my_factorial(0)
[1] 0
> my_factorial(-5)
[1] 0
El factorial de un entero positivo n se define como el producto de
los números enteros positivos desde 1 hasta n. Por convenio el
factorial de 0 es 1.
✓
✗
✗
Segundo reto
Modificar la función, my_factorial(), para que en caso de un número
negativo devuelva un nulo y cuando se le pase 0 la solución sea 1.
Comprobación de inputs: if
my_factorial <- function(n) {
if(n < 0) {
return(NULL)
}
if(n == 0) {
return(1)
}
factorial <- 1
for(i in 1:n) {
factorial <- i * factorial
}
return(factorial)
}
> my_factorial(5)
[1] 120
> my_factorial(0)
[1] 1
> my_factorial(-5)
[1] NULL
> my_factorial("a")
Error in 1:n : NA/NaN argument
In addition: Warning message:
In my_factorial("a") : NAs
introduced by coercion
✓
✓
✓
Tercer reto
Pare la función my_factorial() cuando el valor de entrada no
sea numérico.
Comprobación de inputs: stop / if / assert
my_factorial <- function(n) {
stopifnot(is.numeric(n))
if(n < 0) {
return(NULL)
}
if(n == 0) {
return(1)
}
factorial <- 1
for(i in 1:n) {
factorial <- i * factorial
}
return(factorial)
}
> my_factorial("a")
Error: is.numeric(n) is not TRUE
✓ > my_factorial("a")
Error: Sorry, n must be a number
✓
my_factorial <- function(n) {
if(!is.numeric(n)){stop("Sorry, n must be a number")}
if(n < 0) {
return(NULL)
}
if(n == 0) {
return(1)
}
factorial <- 1
for(i in 1:n) {
factorial <- i * factorial
}
return(factorial)
}
Comprobación de inputs: stop / if / assert
library(assertthat)
my_factorial <- function(n) {
assert_that(
is.numeric(n),
msg = "Sorry, n must be a number"
)
if(n < 0) {
return(NULL)
}
if(n == 0) {
return(1)
}
factorial <- 1
for(i in 1:n) {
factorial <- i * factorial
}
return(factorial)
}
> my_factorial("a")
Error: Sorry, n must be a number
✓ ✓
library(assertthat)
my_factorial <- function(n) {
assert_that(is.numeric(n))
if(n < 0) {
return(NULL)
}
if(n == 0) {
return(1)
}
factorial <- 1
for(i in 1:n) {
factorial <- i * factorial
}
return(factorial)
}
> my_factorial("a")
Error: n is not a numeric or integer vector
Cuarto reto
Crear una función, my_factorial_for_file(), que calcule el
factorial de un número que lee de un archivo csv.
Y al final imprimir: “T ' F ! ”
Manejando excepciones
library(assertthat)
my_factorial_for_file <- function(filename) {
n <- read.csv(filename, header = FALSE)[1, 1]
assert_that(is.numeric(n))
if(n < 0) {
return(NULL)
}
if(n == 0) {
return(1)
}
factorial <- 1
for(i in 1:n) {
factorial <- i * factorial
}
return(factorial)
print("-- That's all folks! --")
}
> my_factorial_for_file("num.csv")
[1] 120
[1] "-- That's all folks! --"
> my_factorial_for_file("num2.csv")
Error in file(file, "rt") : cannot open
the connection In addition: Warning
message:
In file(file, "rt") :
cannot open file 'num2.csv': No such
file or directory
✓
✗
5
num.csv
Manejando excepciones: Try
library(assertthat)
my_factorial_for_file <- function(filename) {
try({
n <- read.csv(filename, header = FALSE)[1, 1]
assert_that(is.numeric(n))
if(n < 0) {
return(NULL)
}
if(n == 0) {
print(1)
}
factorial <- 1
for(i in 1:n) {
factorial <- i * factorial
}
print(factorial)
})
print("-- That's all folks! ---")
}
> my_factorial_for_file("num.csv")
[1] 120
[1] "-- That's all folks! --"
> my_factorial_for_file("num2.csv")
Error in file(file, "rt") : cannot
open the connection
In addition: Warning message:
In file(file, "rt") :
cannot open file 'num2.csv': No
such file or directory
[1] "-- That's all folks! ---"
✓
✓
5
num.csv
Manejando excepciones: Try catch
tryCatch({
expression to be evaluated
}, warning = function(w) {
warning-handler-code
}, error = function(e) {
error-handler-code
}, finally = {
cleanup-code
}
La sintaxis del manejo de excepciones de try catch en R es
similar a la de otros lenguajes:
Manejando excepciones: Try catch
library(assertthat)
my_factorial_for_file <- function(filename) {
tryCatch({
n <- read.csv(filename, header = FALSE)[1, 1]
assert_that(is.numeric(n))
if(n < 0) {
return(NULL)
}
if(n == 0) {
print(1)
}
factorial <- 1
for(i in 1:n) {
factorial <- i * factorial
}
print(factorial)
}, warning = function(w) {
print("Ups, a warning:")
print(w)
}, error = function(e) {
print("There is an error:")
print(e)
}, finally = {
print("-- That's all folks! ---")
})
}
> my_factorial_for_file("num.csv")
[1] 120
[1] "-- That's all folks! --"
> my_factorial_for_file("num2.csv")
[1] "Ups, a warning:"
<simpleWarning in file(file, "rt"):
cannot open file 'num2.csv': No such
file or directory>
[1] "-- That's all folks! ---"
✓
✓
5
num.csv
Comprobaciones una y otra vez sobre lo mismo
> my_factorial(5)
[1] 120
> my_factorial(0)
[1] 1
> my_factorial(-5)
[1] NULL
Sería maravilloso que
cada vez que cambiase
el código se pudiera
evaluar de forma
sencilla
Pixabay
Test unitarios
● Solo deben fallar cuando se introduce un bug
● Los test deben acabar rápidamente, tardar menos de un minuto en ejecutarse
● Debe ser fácil detectar dónde se produce el error para poderlo solucionar
Un test unitario es una secuencia de comandos que evalúa la unidad más pequeña del código
y lo compara con el comportamiento esperado.
Deberían:
● Los test deben ser independientes unos de otros
Una buena nomenclatura
Código que
queremos
testear
foo.R
Código de
testeo
tests/test.foo.R
¡Eh, mira, un test unitario!
library("testthat")
test_that("testing inputs", {
expect_equal(my_factorial(5), 120)
}) > test_file('tests/test.my_factorial.R')
.
DONE =================================
> test_file('tests/test.my_factorial.R')
Error: Test failed: 'testing inputs'
* my_factorial(5) not equal to 120.
1/1 mismatches
[1] 0 - 120 == -120
Si my_factorial(5) devuelve 0
Si my_factorial(5) devuelve 120
Tenemos la expectativa de que my_factorial(5)
devuelva 120
¡Eh, mira, un test unitario!
library("testthat")
test_that("testing inputs", {
expect_equal(my_factorial(5), 120)
expect_equal(my_factorial(0), 1)
expect_equal(my_factorial(-1), NULL)
})
> test_file('tests/test.my_factorial.R')
...
DONE ==================================================================
"testthat: Get Started with Testing" Hadley Wickham
Expectation
Una expectation es una afirmación binaria sobre si un valor es o no lo que se
espera. Sólo en caso de no ser verdadera dará un error.
Hay 11 tipos:
expect_that(x, is_true())
expect_that(x, is_false())
expect_that(x, is_a(y))
expect_that(x, equals(y))
expect_that(x, is_equivalent_to(y))
expect_that(x, is_identical_to(y))
expect_that(x, matches(y))
expect_that(x, prints_text(y))
expect_that(x, shows_message(y))
expect_that(x, gives_warning(y))
expect_that(x, throws_error(y))
expect_true(x)
expect_false(x)
expect_is(x, y)
expect_equal(x, y)
expect_equivalent(x, y)
expect_identical(x, y)
expect_matches(x, y)
expect_output(x, y)
expect_message(x, y)
expect_warning(x, y)
expect_error(x, y)
Full Short curt
Ejemplos de expectations
library("testthat")
test_that("example of expectations", {
expect_equal(1, 1) # pass
expect_equal(1, 1 + 1e-8) # pass
expect_equal(1, 5) # fail
expect_identical(1, 1) # pass
expect_identical(1, 1 + 1e-8) # fail
expect_identical(3, 1 + 2) # pass
expect_identical(0.3, 0.1 + 0.2) # fail
})
> test_file('tests/test.examples.R')
..1.2.3
Failed
---------------------------------------------
1. Failure: example of
expectations(@test.examples.R#6) ------------
1 not equal to 5.
1/1 mismatches
[1] 1 - 5 == -4
2. Failure: example of expectations
(@test.examples.R#8) ------------------------
1 not identical to 1 + 1e-08.
Objects equal but not identical
3. Failure: example of expectations
(@test.examples.R#10) -----------------------
0.3 not identical to 0.1 + 0.2.
Objects equal but not identical
DONE ========================================
1
2
3
4
5
6
7
8
9
10
11
Ejemplos de expectations
library("testthat")
context("testing expectations")
test_that("testing expect_true", {
expect_true(TRUE) # pass
expect_true(FALSE) # fail
})
test_that("testing expect_is", {
model <- lm(c(6:10) ~ c(1:5))
expect_is(model, "lm") # pass
expect_is(model, "numeric") # fail
})
> test_file('tests/test.examples.R')
testing expectations: .1.2
Failed
------------------------------------------------------
1. Failure: testing expect_true (@test.examples2.R#7)
---------
FALSE isn't true.
2. Failure: testing expect_is (@test.examples2.R#13)
---------
`model` inherits from `lm` not `numeric`.
DONE
======================================================
1
2
3
4
5
6
7
8
9
10
11
12
13
14
asserthat::with_mock()
with_mock() ejecuta el código después de sustituir temporalmente las implementaciones de
las funciones del paquete.
Podemos tener en nuestro código funciones que sean difícil de testear.
● Llamadas a un servicio que no está disponible
● Resultados impredecibles al llamar a una función
● Un código que tarde demasiado en ejecutarse
¿Cómo testear en estos casos que el código es el correcto?
Un expectation con with_mock()
library(assertthat)
my_factorial_for_file <- function(filename) {
tryCatch({
n <- read.csv(filename, header = FALSE)[1, 1]
assert_that(is.numeric(n))
if(n < 0) {
return(NULL)
}
if(n == 0) {
print(1)
}
factorial <- 1
for(i in 1:n) {
factorial <- i * factorial
}
print(factorial)
}, warning = function(w) {
print("Ups, a warning:")
print(w)
}, error = function(e) {
print("There is an error:")
print(e)
}, finally = {
# print("-- That's all folks! ---")
})
}
library("testthat")
context("testing my_factorial_for_file()")
test_that("testing inputs", {
with_mock(
read.csv = function(filename, header = FALSE) {data.frame(5)},
{expect_equal(my_factorial_for_file(5), 120)}
)
})
> test_file('tests/test.my_factorial_for_file.R')
testing my_factorial_for_file(): [1] 120
.
DONE
=======================================================================
✓
Varios expectations con with_mock()
library(assertthat)
my_factorial_for_file <- function(filename) {
tryCatch({
n <- read.csv(filename, header = FALSE)[1, 1]
assert_that(is.numeric(n))
factorial <- 1
if(n < 0) {
return(NULL)
}
if(n == 0) {
print(1)
}
for(i in 1:n) {
factorial <- i * factorial
}
print(factorial)
}, warning = function(w) {
print("Ups, a warning:")
print(w)
}, error = function(e) {
print("There is an error:")
print(e)
}, finally = {
# print("-- That's all folks! ---")
})
}
library("testthat")
context("testing my_factorial_for_file()")
test_that("testing inputs", {
with_mock(
read.csv = function(filename, header = FALSE) {data.frame(5)},
{expect_equal(my_factorial_for_file(5), 120)}
)
with_mock(
read.csv = function(filename, header = FALSE) {data.frame(1)},
{expect_equal(my_factorial_for_file(0), 1)}
)
})
> test_file('tests/test.my_factorial_for_file.R')
testing my_factorial_for_file(): [1] 120
.[1] 1
.
DONE
=======================================================================
✓
Último reto
Crear una función, add_one(), que sume uno al número que se le pase.
En caso de que no se le pase un número debe devolver NULL.
Utilizar la metodología Test-Driven Development (TDD).
Workflow (basado en Test-driven development)
Escribe el test
tests/test.foo.R
Escribe el código
mínimo
foo.R
¿Pasa
el
test?
No
Pixabay
 ¿escribir el test antes que el código?
¿Me estás tomando el pelo?
 Por qué escribir el test antes que el código
● Nos aseguramos de obtener el resultado deseado y de que
efectivamente vamos a generar código testeable
● Sirve de guía si no sabes por dónde empezar pero sabes lo que
quieres obtener
● Seamos realistas, lo más seguro es que una vez que el código
realiza lo que queremos nos dará más pereza escribir el test
Test unitarios y paquetes: Test workflow
● Crear un paquete
● Crear test para una función, add_one(), que sume una unidad al número que
se le pase de argumento y en caso de no pasarle un número nos devuelva un
texto
● Crear la función, add_one()
● Estudiar la cobertura de test del paquete
Extractos de "Package Development
with devtools Cheat Sheet"
context("")
test_that("", {
expect_equal()
})
Test unitarios y paquetes: Test workflow (anotaciones)
Plantilla de test unitario:
Test unitarios y paquetes: Test workflow (anotaciones)
File –> New Project -> New Directory -> R Package
devtools::use_testthat() crear carpeta test/testthat
Revisar DESCRIPTION
Crear test.add_one.R
context("test add_one()")
test_that("test add one", {
expect_equal(add_one(5), 6)
expect_equal(add_one(0.5), 1.5)
expect_equal(add_one(-42), -41)
})
test_that("test is not numeric", {
expect_equal(add_one('a'), NULL)
})
Test unitarios y paquetes: Test workflow (anotaciones)
Crear add_one.R
devtools::test()
# add_one.R
add_one <- function(x){
if(!is.numeric(x)){
return(NULL)
}
return(x + 1)
}
library(covr)
cov <- package_coverage()
cov
report(cov)
Test unitarios y paquetes
Unit tests
Pixabay
Devrant
¡Cuidado! El código puede pasar todos los test unitarios y no funcionar por
problemas de integración
Enlaces de interés
● https://journal.r-project.org/archive/2011-1/RJournal_2011-1_Wickham.pdf
● http://courses.had.co.nz/11-devtools/slides/7-testing.pdf
● https://es.slideshare.net/mobile/egoodwintx/unit-testing-in-r-with-testthat-hrug
● https://b-rodrigues.github.io/fput/unit-testing.html#introduction
● https://katherinemwood.github.io/post/testthat/
● http://kbroman.org/Tools4RR/assets/lectures/09_testdebug_withnotes.pdf
● http://sd.jtimothyking.com/2006/07/11/twelve-benefits-of-writing-unit-tests-first/
● https://www.is.uni-freiburg.de/ressourcen/algorithm-design-and-software-engineering-oeffentlicher-zugri
ff/11_softwaretesting.pdf
● https://www.rstudio.com/wp-content/uploads/2015/03/devtools-cheatsheet.pdf
● http://r-pkgs.had.co.nz/tests.html
● http://www.machinegurning.com/rstats/test-driven-development/
● http://stat545.com/packages05_foofactors-package-02.html
Dudas y preguntas
Unit tests
Extra: traceback()
> g <- function(x) x + "a"
> g(0)
Error in x + "a" : non-numeric argument to binary operator
> f <- function(x) g(x)
> f(0)
Error in x + "a" : non-numeric argument to binary operator
> traceback()
2: g(x) at #1
1: f(0)

Más contenido relacionado

La actualidad más candente

Ejercisos condicionales
Ejercisos condicionalesEjercisos condicionales
Ejercisos condicionales
Joshe Varillas
 
comandos
comandoscomandos
comandos
arecerv
 
Instrucciones(raptor, java, c#)
Instrucciones(raptor, java, c#)Instrucciones(raptor, java, c#)
Instrucciones(raptor, java, c#)
ariannalizeeth
 
Interpolaion c++
Interpolaion c++Interpolaion c++
Interpolaion c++
Jean Paul IA
 
Pauta Guia 1(1) Bloc De Notas
Pauta Guia 1(1)   Bloc De NotasPauta Guia 1(1)   Bloc De Notas
Pauta Guia 1(1) Bloc De Notas
Daniel Barraza
 
Trabajo dehoy (1)
Trabajo dehoy (1)Trabajo dehoy (1)
Trabajo dehoy (1)
karlanarvaez109
 

La actualidad más candente (6)

Ejercisos condicionales
Ejercisos condicionalesEjercisos condicionales
Ejercisos condicionales
 
comandos
comandoscomandos
comandos
 
Instrucciones(raptor, java, c#)
Instrucciones(raptor, java, c#)Instrucciones(raptor, java, c#)
Instrucciones(raptor, java, c#)
 
Interpolaion c++
Interpolaion c++Interpolaion c++
Interpolaion c++
 
Pauta Guia 1(1) Bloc De Notas
Pauta Guia 1(1)   Bloc De NotasPauta Guia 1(1)   Bloc De Notas
Pauta Guia 1(1) Bloc De Notas
 
Trabajo dehoy (1)
Trabajo dehoy (1)Trabajo dehoy (1)
Trabajo dehoy (1)
 

Similar a Testeo y depuración en R

Javascript
JavascriptJavascript
Javascript
Daniel Grippo
 
Charla evento TestingUY 2015 - Property-Based Testing Usando Quickcheck, o có...
Charla evento TestingUY 2015 - Property-Based Testing Usando Quickcheck, o có...Charla evento TestingUY 2015 - Property-Based Testing Usando Quickcheck, o có...
Charla evento TestingUY 2015 - Property-Based Testing Usando Quickcheck, o có...
TestingUy
 
Property Based Testing usando QuickCheck
Property Based Testing usando QuickCheckProperty Based Testing usando QuickCheck
Property Based Testing usando QuickCheck
guillecabeza
 
¿En qué la estamos regando en pruebas de software?
¿En qué la estamos regando en pruebas de software?¿En qué la estamos regando en pruebas de software?
¿En qué la estamos regando en pruebas de software?
Agustin Ramos
 
Arreglo unidimensionales y bidimensionales
Arreglo unidimensionales y bidimensionalesArreglo unidimensionales y bidimensionales
Arreglo unidimensionales y bidimensionales
Marco Garay
 
Fundamentos De Algoritmia
Fundamentos De AlgoritmiaFundamentos De Algoritmia
Fundamentos De Algoritmia
cckokyco
 
Intro_Matlab_1.pdf
Intro_Matlab_1.pdfIntro_Matlab_1.pdf
Intro_Matlab_1.pdf
MiguelBriones24
 
Php
PhpPhp
Quiero hacer ágil, ¿y ahora qué: Java, Ruby o Scala?
Quiero hacer ágil, ¿y ahora qué: Java, Ruby o Scala?Quiero hacer ágil, ¿y ahora qué: Java, Ruby o Scala?
Quiero hacer ágil, ¿y ahora qué: Java, Ruby o Scala?
Agile Spain
 
Clase 6
Clase 6Clase 6
Tipos basicos
Tipos basicosTipos basicos
Tipos basicos
Enric Cecilla Real
 
Machine Learning con Tensorflow y R, presentado por RStudio
Machine Learning con Tensorflow y R, presentado por RStudioMachine Learning con Tensorflow y R, presentado por RStudio
Machine Learning con Tensorflow y R, presentado por RStudio
Software Guru
 
Factorial en C++
Factorial en C++Factorial en C++
Factorial en C++
KareliaRivas
 
32773 php-basico
32773 php-basico32773 php-basico
32773 php-basico
Luis Gatica Espina
 
Ruby
RubyRuby
Ruby
ThirdWay
 
Elementos del Hardware y Software
Elementos del Hardware y SoftwareElementos del Hardware y Software
Elementos del Hardware y Software
carlosadrianev
 
C curso intr
C curso intr C curso intr
C curso intr
leo24012
 
Clase 7
Clase 7Clase 7
Clase 7
esvin Rey
 
Curso TDD Ruby on Rails #03: Tests unitarios
Curso TDD Ruby on Rails #03: Tests unitariosCurso TDD Ruby on Rails #03: Tests unitarios
Curso TDD Ruby on Rails #03: Tests unitarios
Alberto Perdomo
 
Subporgramacion
SubporgramacionSubporgramacion
Subporgramacion
guest5ac5ce3
 

Similar a Testeo y depuración en R (20)

Javascript
JavascriptJavascript
Javascript
 
Charla evento TestingUY 2015 - Property-Based Testing Usando Quickcheck, o có...
Charla evento TestingUY 2015 - Property-Based Testing Usando Quickcheck, o có...Charla evento TestingUY 2015 - Property-Based Testing Usando Quickcheck, o có...
Charla evento TestingUY 2015 - Property-Based Testing Usando Quickcheck, o có...
 
Property Based Testing usando QuickCheck
Property Based Testing usando QuickCheckProperty Based Testing usando QuickCheck
Property Based Testing usando QuickCheck
 
¿En qué la estamos regando en pruebas de software?
¿En qué la estamos regando en pruebas de software?¿En qué la estamos regando en pruebas de software?
¿En qué la estamos regando en pruebas de software?
 
Arreglo unidimensionales y bidimensionales
Arreglo unidimensionales y bidimensionalesArreglo unidimensionales y bidimensionales
Arreglo unidimensionales y bidimensionales
 
Fundamentos De Algoritmia
Fundamentos De AlgoritmiaFundamentos De Algoritmia
Fundamentos De Algoritmia
 
Intro_Matlab_1.pdf
Intro_Matlab_1.pdfIntro_Matlab_1.pdf
Intro_Matlab_1.pdf
 
Php
PhpPhp
Php
 
Quiero hacer ágil, ¿y ahora qué: Java, Ruby o Scala?
Quiero hacer ágil, ¿y ahora qué: Java, Ruby o Scala?Quiero hacer ágil, ¿y ahora qué: Java, Ruby o Scala?
Quiero hacer ágil, ¿y ahora qué: Java, Ruby o Scala?
 
Clase 6
Clase 6Clase 6
Clase 6
 
Tipos basicos
Tipos basicosTipos basicos
Tipos basicos
 
Machine Learning con Tensorflow y R, presentado por RStudio
Machine Learning con Tensorflow y R, presentado por RStudioMachine Learning con Tensorflow y R, presentado por RStudio
Machine Learning con Tensorflow y R, presentado por RStudio
 
Factorial en C++
Factorial en C++Factorial en C++
Factorial en C++
 
32773 php-basico
32773 php-basico32773 php-basico
32773 php-basico
 
Ruby
RubyRuby
Ruby
 
Elementos del Hardware y Software
Elementos del Hardware y SoftwareElementos del Hardware y Software
Elementos del Hardware y Software
 
C curso intr
C curso intr C curso intr
C curso intr
 
Clase 7
Clase 7Clase 7
Clase 7
 
Curso TDD Ruby on Rails #03: Tests unitarios
Curso TDD Ruby on Rails #03: Tests unitariosCurso TDD Ruby on Rails #03: Tests unitarios
Curso TDD Ruby on Rails #03: Tests unitarios
 
Subporgramacion
SubporgramacionSubporgramacion
Subporgramacion
 

Último

Manual Web soporte y mantenimiento de equipo de computo
Manual Web soporte y mantenimiento de equipo de computoManual Web soporte y mantenimiento de equipo de computo
Manual Web soporte y mantenimiento de equipo de computo
mantenimientocarbra6
 
Programming & Artificial Intelligence ebook.pdf
Programming & Artificial Intelligence ebook.pdfProgramming & Artificial Intelligence ebook.pdf
Programming & Artificial Intelligence ebook.pdf
Manuel Diaz
 
PLAN DE MANTENMIENTO preventivo de un equipo de computo.pdf
PLAN DE MANTENMIENTO preventivo de un equipo de computo.pdfPLAN DE MANTENMIENTO preventivo de un equipo de computo.pdf
PLAN DE MANTENMIENTO preventivo de un equipo de computo.pdf
70244530
 
Nuevos tiempos, nuevos espacios.docxdsdsad
Nuevos tiempos, nuevos espacios.docxdsdsadNuevos tiempos, nuevos espacios.docxdsdsad
Nuevos tiempos, nuevos espacios.docxdsdsad
larapalaciosmonzon28
 
computacion global 3.pdf pARA TERCER GRADO
computacion global 3.pdf pARA TERCER GRADOcomputacion global 3.pdf pARA TERCER GRADO
computacion global 3.pdf pARA TERCER GRADO
YaniEscobar2
 
Catalogo Refrigeracion Miele Distribuidor Oficial Amado Salvador Valencia
Catalogo Refrigeracion Miele Distribuidor Oficial Amado Salvador ValenciaCatalogo Refrigeracion Miele Distribuidor Oficial Amado Salvador Valencia
Catalogo Refrigeracion Miele Distribuidor Oficial Amado Salvador Valencia
AMADO SALVADOR
 
Infografia TCP/IP (Transmission Control Protocol/Internet Protocol)
Infografia TCP/IP (Transmission Control Protocol/Internet Protocol)Infografia TCP/IP (Transmission Control Protocol/Internet Protocol)
Infografia TCP/IP (Transmission Control Protocol/Internet Protocol)
codesiret
 
EXAMEN DE TOPOGRAFIA RESUELTO-2017 CURSO DE UNIVERSIDAD
EXAMEN DE TOPOGRAFIA RESUELTO-2017 CURSO DE UNIVERSIDADEXAMEN DE TOPOGRAFIA RESUELTO-2017 CURSO DE UNIVERSIDAD
EXAMEN DE TOPOGRAFIA RESUELTO-2017 CURSO DE UNIVERSIDAD
AngelCristhianMB
 
Informació Projecte Iniciativa TIC HPE.pdf
Informació Projecte Iniciativa TIC HPE.pdfInformació Projecte Iniciativa TIC HPE.pdf
Informació Projecte Iniciativa TIC HPE.pdf
Festibity
 
TIC en educacion.rtf.docxlolololololololo
TIC en educacion.rtf.docxlolololololololoTIC en educacion.rtf.docxlolololololololo
TIC en educacion.rtf.docxlolololololololo
KukiiSanchez
 
Manual de soporte y mantenimiento de equipo de cómputo
Manual de soporte y mantenimiento de equipo de cómputoManual de soporte y mantenimiento de equipo de cómputo
Manual de soporte y mantenimiento de equipo de cómputo
doctorsoluciones34
 
edublogs info.docx asdasfasfsawqrdqwfqwfqwfq
edublogs info.docx asdasfasfsawqrdqwfqwfqwfqedublogs info.docx asdasfasfsawqrdqwfqwfqwfq
edublogs info.docx asdasfasfsawqrdqwfqwfqwfq
larapalaciosmonzon28
 
Projecte Iniciativa TIC 2024 KAWARU CONSULTING. inCV.pdf
Projecte Iniciativa TIC 2024 KAWARU CONSULTING. inCV.pdfProjecte Iniciativa TIC 2024 KAWARU CONSULTING. inCV.pdf
Projecte Iniciativa TIC 2024 KAWARU CONSULTING. inCV.pdf
Festibity
 
Refrigeradores Samsung Modo Test y Forzado
Refrigeradores Samsung Modo Test y ForzadoRefrigeradores Samsung Modo Test y Forzado
Refrigeradores Samsung Modo Test y Forzado
NicandroMartinez2
 
Presentación Seguridad Digital Profesional Azul Oscuro (1).pdf
Presentación Seguridad Digital Profesional Azul Oscuro (1).pdfPresentación Seguridad Digital Profesional Azul Oscuro (1).pdf
Presentación Seguridad Digital Profesional Azul Oscuro (1).pdf
giampierdiaz5
 
Second Life, informe de actividad del maestro Tapia
Second Life, informe de actividad del maestro TapiaSecond Life, informe de actividad del maestro Tapia
Second Life, informe de actividad del maestro Tapia
al050121024
 
Modo test refrigeradores y codigos de errores 2018 V2.pdf
Modo test refrigeradores y codigos de errores 2018 V2.pdfModo test refrigeradores y codigos de errores 2018 V2.pdf
Modo test refrigeradores y codigos de errores 2018 V2.pdf
ranierglez
 
Mantenimiento de sistemas eléctricos y electrónicosarticles-241712_recurso_6....
Mantenimiento de sistemas eléctricos y electrónicosarticles-241712_recurso_6....Mantenimiento de sistemas eléctricos y electrónicosarticles-241712_recurso_6....
Mantenimiento de sistemas eléctricos y electrónicosarticles-241712_recurso_6....
MiguelAtencio10
 
mantenimiento de chasis y carroceria1.pptx
mantenimiento de chasis y carroceria1.pptxmantenimiento de chasis y carroceria1.pptx
mantenimiento de chasis y carroceria1.pptx
MiguelAtencio10
 
REVISTA TECNOLOGICA PARA EL DESARROLLO HUMANO
REVISTA TECNOLOGICA PARA EL DESARROLLO HUMANOREVISTA TECNOLOGICA PARA EL DESARROLLO HUMANO
REVISTA TECNOLOGICA PARA EL DESARROLLO HUMANO
gisellearanguren1
 

Último (20)

Manual Web soporte y mantenimiento de equipo de computo
Manual Web soporte y mantenimiento de equipo de computoManual Web soporte y mantenimiento de equipo de computo
Manual Web soporte y mantenimiento de equipo de computo
 
Programming & Artificial Intelligence ebook.pdf
Programming & Artificial Intelligence ebook.pdfProgramming & Artificial Intelligence ebook.pdf
Programming & Artificial Intelligence ebook.pdf
 
PLAN DE MANTENMIENTO preventivo de un equipo de computo.pdf
PLAN DE MANTENMIENTO preventivo de un equipo de computo.pdfPLAN DE MANTENMIENTO preventivo de un equipo de computo.pdf
PLAN DE MANTENMIENTO preventivo de un equipo de computo.pdf
 
Nuevos tiempos, nuevos espacios.docxdsdsad
Nuevos tiempos, nuevos espacios.docxdsdsadNuevos tiempos, nuevos espacios.docxdsdsad
Nuevos tiempos, nuevos espacios.docxdsdsad
 
computacion global 3.pdf pARA TERCER GRADO
computacion global 3.pdf pARA TERCER GRADOcomputacion global 3.pdf pARA TERCER GRADO
computacion global 3.pdf pARA TERCER GRADO
 
Catalogo Refrigeracion Miele Distribuidor Oficial Amado Salvador Valencia
Catalogo Refrigeracion Miele Distribuidor Oficial Amado Salvador ValenciaCatalogo Refrigeracion Miele Distribuidor Oficial Amado Salvador Valencia
Catalogo Refrigeracion Miele Distribuidor Oficial Amado Salvador Valencia
 
Infografia TCP/IP (Transmission Control Protocol/Internet Protocol)
Infografia TCP/IP (Transmission Control Protocol/Internet Protocol)Infografia TCP/IP (Transmission Control Protocol/Internet Protocol)
Infografia TCP/IP (Transmission Control Protocol/Internet Protocol)
 
EXAMEN DE TOPOGRAFIA RESUELTO-2017 CURSO DE UNIVERSIDAD
EXAMEN DE TOPOGRAFIA RESUELTO-2017 CURSO DE UNIVERSIDADEXAMEN DE TOPOGRAFIA RESUELTO-2017 CURSO DE UNIVERSIDAD
EXAMEN DE TOPOGRAFIA RESUELTO-2017 CURSO DE UNIVERSIDAD
 
Informació Projecte Iniciativa TIC HPE.pdf
Informació Projecte Iniciativa TIC HPE.pdfInformació Projecte Iniciativa TIC HPE.pdf
Informació Projecte Iniciativa TIC HPE.pdf
 
TIC en educacion.rtf.docxlolololololololo
TIC en educacion.rtf.docxlolololololololoTIC en educacion.rtf.docxlolololololololo
TIC en educacion.rtf.docxlolololololololo
 
Manual de soporte y mantenimiento de equipo de cómputo
Manual de soporte y mantenimiento de equipo de cómputoManual de soporte y mantenimiento de equipo de cómputo
Manual de soporte y mantenimiento de equipo de cómputo
 
edublogs info.docx asdasfasfsawqrdqwfqwfqwfq
edublogs info.docx asdasfasfsawqrdqwfqwfqwfqedublogs info.docx asdasfasfsawqrdqwfqwfqwfq
edublogs info.docx asdasfasfsawqrdqwfqwfqwfq
 
Projecte Iniciativa TIC 2024 KAWARU CONSULTING. inCV.pdf
Projecte Iniciativa TIC 2024 KAWARU CONSULTING. inCV.pdfProjecte Iniciativa TIC 2024 KAWARU CONSULTING. inCV.pdf
Projecte Iniciativa TIC 2024 KAWARU CONSULTING. inCV.pdf
 
Refrigeradores Samsung Modo Test y Forzado
Refrigeradores Samsung Modo Test y ForzadoRefrigeradores Samsung Modo Test y Forzado
Refrigeradores Samsung Modo Test y Forzado
 
Presentación Seguridad Digital Profesional Azul Oscuro (1).pdf
Presentación Seguridad Digital Profesional Azul Oscuro (1).pdfPresentación Seguridad Digital Profesional Azul Oscuro (1).pdf
Presentación Seguridad Digital Profesional Azul Oscuro (1).pdf
 
Second Life, informe de actividad del maestro Tapia
Second Life, informe de actividad del maestro TapiaSecond Life, informe de actividad del maestro Tapia
Second Life, informe de actividad del maestro Tapia
 
Modo test refrigeradores y codigos de errores 2018 V2.pdf
Modo test refrigeradores y codigos de errores 2018 V2.pdfModo test refrigeradores y codigos de errores 2018 V2.pdf
Modo test refrigeradores y codigos de errores 2018 V2.pdf
 
Mantenimiento de sistemas eléctricos y electrónicosarticles-241712_recurso_6....
Mantenimiento de sistemas eléctricos y electrónicosarticles-241712_recurso_6....Mantenimiento de sistemas eléctricos y electrónicosarticles-241712_recurso_6....
Mantenimiento de sistemas eléctricos y electrónicosarticles-241712_recurso_6....
 
mantenimiento de chasis y carroceria1.pptx
mantenimiento de chasis y carroceria1.pptxmantenimiento de chasis y carroceria1.pptx
mantenimiento de chasis y carroceria1.pptx
 
REVISTA TECNOLOGICA PARA EL DESARROLLO HUMANO
REVISTA TECNOLOGICA PARA EL DESARROLLO HUMANOREVISTA TECNOLOGICA PARA EL DESARROLLO HUMANO
REVISTA TECNOLOGICA PARA EL DESARROLLO HUMANO
 

Testeo y depuración en R

  • 1. Testeo y depuración en R Primera línea de defensa contra los bugs Virginia Peón García
  • 2. Pixabay Nunca me encontrarán escondido en el código, Muahahaha
  • 3. ● Depurando (print) Temario ● Comprobación de inputs de una función (if / stop / assert) ● Manejando excepciones (try / try catch) ● Test unitarios ○ Características y ejemplos ○ Metodología TDD
  • 4. Presentación a través de retos En la exposición voy a ir presentando retos que resolver. Cuando se alcance el resultado saldrá:
  • 5. Primer reto Crear una función, my_factorial(), que calcule el factorial de un número. El factorial de un entero positivo n se define como el producto de los números enteros positivos desde 1 hasta n. Por ejemplo, El factorial de 5 es: 1*2*3*4*5 = 120
  • 6. Primera versión my_factorial <- function(n) { factorial <- 0 for(i in 1:n) { factorial <- i * factorial } return(factorial) } > my_factorial(5) [1] 0 ✗
  • 7. Depurando con print my_factorial <- function(n) { factorial <- 0 for(i in 1:n) { factorial <- i * factorial } return(factorial) } > my_factorial(5) [1] "1 = > 0" [1] "2 = > 0" [1] "3 = > 0" [1] "4 = > 0" [1] "5 = > 0" [1] 0 print(paste(i, factorial, sep = " => ")) ✗
  • 8. Depurando con print my_factorial <- function(n) { factorial <- 0 for(i in 1:n) { factorial <- i * factorial print(paste(i, factorial, sep = " => ")) } return(factorial) } factorial <- 1 ✓ > my_factorial(5) [1] "1 = > 1" [1] "2 = > 2" [1] "3 = > 6" [1] "4 = > 24" [1] "5 = > 120" [1] 120
  • 9. Version depurada my_factorial <- function(n) { factorial <- 1 for(i in 1:n) { factorial <- i * factorial } return(factorial) } > my_factorial(5) [1] 120 ✓
  • 10. Comprobación de inputs > my_factorial(5) [1] 120 > my_factorial(0) [1] 0 > my_factorial(-5) [1] 0 El factorial de un entero positivo n se define como el producto de los números enteros positivos desde 1 hasta n. Por convenio el factorial de 0 es 1. ✓ ✗ ✗
  • 11. Segundo reto Modificar la función, my_factorial(), para que en caso de un número negativo devuelva un nulo y cuando se le pase 0 la solución sea 1.
  • 12. Comprobación de inputs: if my_factorial <- function(n) { if(n < 0) { return(NULL) } if(n == 0) { return(1) } factorial <- 1 for(i in 1:n) { factorial <- i * factorial } return(factorial) } > my_factorial(5) [1] 120 > my_factorial(0) [1] 1 > my_factorial(-5) [1] NULL > my_factorial("a") Error in 1:n : NA/NaN argument In addition: Warning message: In my_factorial("a") : NAs introduced by coercion ✓ ✓ ✓
  • 13. Tercer reto Pare la función my_factorial() cuando el valor de entrada no sea numérico.
  • 14. Comprobación de inputs: stop / if / assert my_factorial <- function(n) { stopifnot(is.numeric(n)) if(n < 0) { return(NULL) } if(n == 0) { return(1) } factorial <- 1 for(i in 1:n) { factorial <- i * factorial } return(factorial) } > my_factorial("a") Error: is.numeric(n) is not TRUE ✓ > my_factorial("a") Error: Sorry, n must be a number ✓ my_factorial <- function(n) { if(!is.numeric(n)){stop("Sorry, n must be a number")} if(n < 0) { return(NULL) } if(n == 0) { return(1) } factorial <- 1 for(i in 1:n) { factorial <- i * factorial } return(factorial) }
  • 15. Comprobación de inputs: stop / if / assert library(assertthat) my_factorial <- function(n) { assert_that( is.numeric(n), msg = "Sorry, n must be a number" ) if(n < 0) { return(NULL) } if(n == 0) { return(1) } factorial <- 1 for(i in 1:n) { factorial <- i * factorial } return(factorial) } > my_factorial("a") Error: Sorry, n must be a number ✓ ✓ library(assertthat) my_factorial <- function(n) { assert_that(is.numeric(n)) if(n < 0) { return(NULL) } if(n == 0) { return(1) } factorial <- 1 for(i in 1:n) { factorial <- i * factorial } return(factorial) } > my_factorial("a") Error: n is not a numeric or integer vector
  • 16. Cuarto reto Crear una función, my_factorial_for_file(), que calcule el factorial de un número que lee de un archivo csv. Y al final imprimir: “T ' F ! ”
  • 17. Manejando excepciones library(assertthat) my_factorial_for_file <- function(filename) { n <- read.csv(filename, header = FALSE)[1, 1] assert_that(is.numeric(n)) if(n < 0) { return(NULL) } if(n == 0) { return(1) } factorial <- 1 for(i in 1:n) { factorial <- i * factorial } return(factorial) print("-- That's all folks! --") } > my_factorial_for_file("num.csv") [1] 120 [1] "-- That's all folks! --" > my_factorial_for_file("num2.csv") Error in file(file, "rt") : cannot open the connection In addition: Warning message: In file(file, "rt") : cannot open file 'num2.csv': No such file or directory ✓ ✗ 5 num.csv
  • 18. Manejando excepciones: Try library(assertthat) my_factorial_for_file <- function(filename) { try({ n <- read.csv(filename, header = FALSE)[1, 1] assert_that(is.numeric(n)) if(n < 0) { return(NULL) } if(n == 0) { print(1) } factorial <- 1 for(i in 1:n) { factorial <- i * factorial } print(factorial) }) print("-- That's all folks! ---") } > my_factorial_for_file("num.csv") [1] 120 [1] "-- That's all folks! --" > my_factorial_for_file("num2.csv") Error in file(file, "rt") : cannot open the connection In addition: Warning message: In file(file, "rt") : cannot open file 'num2.csv': No such file or directory [1] "-- That's all folks! ---" ✓ ✓ 5 num.csv
  • 19. Manejando excepciones: Try catch tryCatch({ expression to be evaluated }, warning = function(w) { warning-handler-code }, error = function(e) { error-handler-code }, finally = { cleanup-code } La sintaxis del manejo de excepciones de try catch en R es similar a la de otros lenguajes:
  • 20. Manejando excepciones: Try catch library(assertthat) my_factorial_for_file <- function(filename) { tryCatch({ n <- read.csv(filename, header = FALSE)[1, 1] assert_that(is.numeric(n)) if(n < 0) { return(NULL) } if(n == 0) { print(1) } factorial <- 1 for(i in 1:n) { factorial <- i * factorial } print(factorial) }, warning = function(w) { print("Ups, a warning:") print(w) }, error = function(e) { print("There is an error:") print(e) }, finally = { print("-- That's all folks! ---") }) } > my_factorial_for_file("num.csv") [1] 120 [1] "-- That's all folks! --" > my_factorial_for_file("num2.csv") [1] "Ups, a warning:" <simpleWarning in file(file, "rt"): cannot open file 'num2.csv': No such file or directory> [1] "-- That's all folks! ---" ✓ ✓ 5 num.csv
  • 21. Comprobaciones una y otra vez sobre lo mismo > my_factorial(5) [1] 120 > my_factorial(0) [1] 1 > my_factorial(-5) [1] NULL
  • 22. Sería maravilloso que cada vez que cambiase el código se pudiera evaluar de forma sencilla Pixabay
  • 23. Test unitarios ● Solo deben fallar cuando se introduce un bug ● Los test deben acabar rápidamente, tardar menos de un minuto en ejecutarse ● Debe ser fácil detectar dónde se produce el error para poderlo solucionar Un test unitario es una secuencia de comandos que evalúa la unidad más pequeña del código y lo compara con el comportamiento esperado. Deberían: ● Los test deben ser independientes unos de otros
  • 24. Una buena nomenclatura Código que queremos testear foo.R Código de testeo tests/test.foo.R
  • 25. ¡Eh, mira, un test unitario! library("testthat") test_that("testing inputs", { expect_equal(my_factorial(5), 120) }) > test_file('tests/test.my_factorial.R') . DONE ================================= > test_file('tests/test.my_factorial.R') Error: Test failed: 'testing inputs' * my_factorial(5) not equal to 120. 1/1 mismatches [1] 0 - 120 == -120 Si my_factorial(5) devuelve 0 Si my_factorial(5) devuelve 120 Tenemos la expectativa de que my_factorial(5) devuelva 120
  • 26. ¡Eh, mira, un test unitario! library("testthat") test_that("testing inputs", { expect_equal(my_factorial(5), 120) expect_equal(my_factorial(0), 1) expect_equal(my_factorial(-1), NULL) }) > test_file('tests/test.my_factorial.R') ... DONE ==================================================================
  • 27. "testthat: Get Started with Testing" Hadley Wickham Expectation Una expectation es una afirmación binaria sobre si un valor es o no lo que se espera. Sólo en caso de no ser verdadera dará un error. Hay 11 tipos: expect_that(x, is_true()) expect_that(x, is_false()) expect_that(x, is_a(y)) expect_that(x, equals(y)) expect_that(x, is_equivalent_to(y)) expect_that(x, is_identical_to(y)) expect_that(x, matches(y)) expect_that(x, prints_text(y)) expect_that(x, shows_message(y)) expect_that(x, gives_warning(y)) expect_that(x, throws_error(y)) expect_true(x) expect_false(x) expect_is(x, y) expect_equal(x, y) expect_equivalent(x, y) expect_identical(x, y) expect_matches(x, y) expect_output(x, y) expect_message(x, y) expect_warning(x, y) expect_error(x, y) Full Short curt
  • 28. Ejemplos de expectations library("testthat") test_that("example of expectations", { expect_equal(1, 1) # pass expect_equal(1, 1 + 1e-8) # pass expect_equal(1, 5) # fail expect_identical(1, 1) # pass expect_identical(1, 1 + 1e-8) # fail expect_identical(3, 1 + 2) # pass expect_identical(0.3, 0.1 + 0.2) # fail }) > test_file('tests/test.examples.R') ..1.2.3 Failed --------------------------------------------- 1. Failure: example of expectations(@test.examples.R#6) ------------ 1 not equal to 5. 1/1 mismatches [1] 1 - 5 == -4 2. Failure: example of expectations (@test.examples.R#8) ------------------------ 1 not identical to 1 + 1e-08. Objects equal but not identical 3. Failure: example of expectations (@test.examples.R#10) ----------------------- 0.3 not identical to 0.1 + 0.2. Objects equal but not identical DONE ======================================== 1 2 3 4 5 6 7 8 9 10 11
  • 29. Ejemplos de expectations library("testthat") context("testing expectations") test_that("testing expect_true", { expect_true(TRUE) # pass expect_true(FALSE) # fail }) test_that("testing expect_is", { model <- lm(c(6:10) ~ c(1:5)) expect_is(model, "lm") # pass expect_is(model, "numeric") # fail }) > test_file('tests/test.examples.R') testing expectations: .1.2 Failed ------------------------------------------------------ 1. Failure: testing expect_true (@test.examples2.R#7) --------- FALSE isn't true. 2. Failure: testing expect_is (@test.examples2.R#13) --------- `model` inherits from `lm` not `numeric`. DONE ====================================================== 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  • 30. asserthat::with_mock() with_mock() ejecuta el código después de sustituir temporalmente las implementaciones de las funciones del paquete. Podemos tener en nuestro código funciones que sean difícil de testear. ● Llamadas a un servicio que no está disponible ● Resultados impredecibles al llamar a una función ● Un código que tarde demasiado en ejecutarse ¿Cómo testear en estos casos que el código es el correcto?
  • 31. Un expectation con with_mock() library(assertthat) my_factorial_for_file <- function(filename) { tryCatch({ n <- read.csv(filename, header = FALSE)[1, 1] assert_that(is.numeric(n)) if(n < 0) { return(NULL) } if(n == 0) { print(1) } factorial <- 1 for(i in 1:n) { factorial <- i * factorial } print(factorial) }, warning = function(w) { print("Ups, a warning:") print(w) }, error = function(e) { print("There is an error:") print(e) }, finally = { # print("-- That's all folks! ---") }) } library("testthat") context("testing my_factorial_for_file()") test_that("testing inputs", { with_mock( read.csv = function(filename, header = FALSE) {data.frame(5)}, {expect_equal(my_factorial_for_file(5), 120)} ) }) > test_file('tests/test.my_factorial_for_file.R') testing my_factorial_for_file(): [1] 120 . DONE ======================================================================= ✓
  • 32. Varios expectations con with_mock() library(assertthat) my_factorial_for_file <- function(filename) { tryCatch({ n <- read.csv(filename, header = FALSE)[1, 1] assert_that(is.numeric(n)) factorial <- 1 if(n < 0) { return(NULL) } if(n == 0) { print(1) } for(i in 1:n) { factorial <- i * factorial } print(factorial) }, warning = function(w) { print("Ups, a warning:") print(w) }, error = function(e) { print("There is an error:") print(e) }, finally = { # print("-- That's all folks! ---") }) } library("testthat") context("testing my_factorial_for_file()") test_that("testing inputs", { with_mock( read.csv = function(filename, header = FALSE) {data.frame(5)}, {expect_equal(my_factorial_for_file(5), 120)} ) with_mock( read.csv = function(filename, header = FALSE) {data.frame(1)}, {expect_equal(my_factorial_for_file(0), 1)} ) }) > test_file('tests/test.my_factorial_for_file.R') testing my_factorial_for_file(): [1] 120 .[1] 1 . DONE ======================================================================= ✓
  • 33. Último reto Crear una función, add_one(), que sume uno al número que se le pase. En caso de que no se le pase un número debe devolver NULL. Utilizar la metodología Test-Driven Development (TDD).
  • 34. Workflow (basado en Test-driven development) Escribe el test tests/test.foo.R Escribe el código mínimo foo.R ¿Pasa el test? No
  • 35. Pixabay  ¿escribir el test antes que el código? ¿Me estás tomando el pelo?
  • 36.  Por qué escribir el test antes que el código ● Nos aseguramos de obtener el resultado deseado y de que efectivamente vamos a generar código testeable ● Sirve de guía si no sabes por dónde empezar pero sabes lo que quieres obtener ● Seamos realistas, lo más seguro es que una vez que el código realiza lo que queremos nos dará más pereza escribir el test
  • 37. Test unitarios y paquetes: Test workflow ● Crear un paquete ● Crear test para una función, add_one(), que sume una unidad al número que se le pase de argumento y en caso de no pasarle un número nos devuelva un texto ● Crear la función, add_one() ● Estudiar la cobertura de test del paquete
  • 38.
  • 39. Extractos de "Package Development with devtools Cheat Sheet"
  • 40. context("") test_that("", { expect_equal() }) Test unitarios y paquetes: Test workflow (anotaciones) Plantilla de test unitario:
  • 41. Test unitarios y paquetes: Test workflow (anotaciones) File –> New Project -> New Directory -> R Package devtools::use_testthat() crear carpeta test/testthat Revisar DESCRIPTION Crear test.add_one.R context("test add_one()") test_that("test add one", { expect_equal(add_one(5), 6) expect_equal(add_one(0.5), 1.5) expect_equal(add_one(-42), -41) }) test_that("test is not numeric", { expect_equal(add_one('a'), NULL) })
  • 42. Test unitarios y paquetes: Test workflow (anotaciones) Crear add_one.R devtools::test() # add_one.R add_one <- function(x){ if(!is.numeric(x)){ return(NULL) } return(x + 1) } library(covr) cov <- package_coverage() cov report(cov)
  • 43. Test unitarios y paquetes
  • 44.
  • 46. Devrant ¡Cuidado! El código puede pasar todos los test unitarios y no funcionar por problemas de integración
  • 47. Enlaces de interés ● https://journal.r-project.org/archive/2011-1/RJournal_2011-1_Wickham.pdf ● http://courses.had.co.nz/11-devtools/slides/7-testing.pdf ● https://es.slideshare.net/mobile/egoodwintx/unit-testing-in-r-with-testthat-hrug ● https://b-rodrigues.github.io/fput/unit-testing.html#introduction ● https://katherinemwood.github.io/post/testthat/ ● http://kbroman.org/Tools4RR/assets/lectures/09_testdebug_withnotes.pdf ● http://sd.jtimothyking.com/2006/07/11/twelve-benefits-of-writing-unit-tests-first/ ● https://www.is.uni-freiburg.de/ressourcen/algorithm-design-and-software-engineering-oeffentlicher-zugri ff/11_softwaretesting.pdf ● https://www.rstudio.com/wp-content/uploads/2015/03/devtools-cheatsheet.pdf ● http://r-pkgs.had.co.nz/tests.html ● http://www.machinegurning.com/rstats/test-driven-development/ ● http://stat545.com/packages05_foofactors-package-02.html
  • 49. Extra: traceback() > g <- function(x) x + "a" > g(0) Error in x + "a" : non-numeric argument to binary operator > f <- function(x) g(x) > f(0) Error in x + "a" : non-numeric argument to binary operator > traceback() 2: g(x) at #1 1: f(0)