SlideShare una empresa de Scribd logo
1 de 56
Descargar para leer sin conexión
MADRID · NOV 18-19 · 2016
Why Using
by @andres_viedma
instead of
in your Java Tests
Andrés ViedmaAndrés Viedma
@andres_viedma@andres_viedma
01 SPOCK?
A testing framework
Tests are written in
100% compatible with Java code
Runs on
http://spockframework.org/
A basic JUnit test
@Test
public void thatAddAPositiveNumberToZeroReturnsTheSamePositiveNumber()
throws Exception {
int positiveNumber = 23;
int zero = 0;
int result = zero + positiveNumber;
assertEquals(positiveNumber, result);
}
A basic Spock test
def "Add a positive number to zero returns the same positive number"() {
given:
def positiveNumber = 23
def zero = 0
when:
def result = zero + positiveNumber
then:
result == positiveNumber
}
A basic Spock test
def "Add a positive number to zero returns the same positive number"() {
given:
def positiveNumber = 23
def zero = 0
when:
def result = zero + positiveNumber
then:
result == positiveNumber
}
A basic Spock test
DSL
def "Add a positive number to zero returns the same positive number"() {
given:
def positiveNumber = 23
def zero = 0
when:
def result = zero + positiveNumber
then:
result == positiveNumber
}
String literals
def "Add a positive number to zero returns the same positive number"() {
(...)
}
@Test
public void thatAddAPositiveNumberToZeroReturnsTheSamePositiveNumber()
throws Exception {
(...)
}
String literals
def "Add a positive number to zero returns the same positive number"() {
(...)
}
@Test
public void thatAddAPositiveNumberToZeroReturnsTheSamePositiveNumber()
throws Exception {
(...)
}
def "En un lugar de la Mancha, de cuyo nombre no quiero acordarme,
no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero,
adarga antigua, rocín flaco y galgo corredor. "() {
(...)
}
Spock Blocks
given:
def positiveNumber = 23
def zero = 0
when:
def result = zero + positiveNumber
then:
result == positiveNumber
int positiveNumber = 23;
int zero = 0;
int result = zero + positiveNumber;
assertEquals(positiveNumber, result);
Programming vs. Specification
Spock Blocks
given:
def positiveNumber = 23
def zero = 0
when:
def result = zero + positiveNumber
then:
result == positiveNumber
// Given
int positiveNumber = 23;
int zero = 0;
// When
int result = zero + positiveNumber;
// Then
assertEquals(positiveNumber, result);
Compilation check
Programming vs. Specification
Documented Spock Blocks
given: "A positive number"
def positiveNumber = 23
and: "Well... a SPECTACULAR zero"
def zero = 0
when: "The number is added to zero"
def result = zero + positiveNumber
then: "The result is the same number"
result == positiveNumber
int positiveNumber = 23;
int zero = 0;
int result = zero + positiveNumber;
assertEquals(positiveNumber, result);
Documents purpose
Helps thinking
expect block
given: "A positive number"
def positiveNumber = 23
expect: "That added to zero results the same number"
zero + positiveNumber == positiveNumber
Replaces when-then for simple
functional tests
Expectations (then / expect)
given:
def positiveNumber = 23
def zero = 0
when:
def result = zero + positiveNumber
then:
result == positiveNumber
int positiveNumber = 23;
int zero = 0;
int result = zero + positiveNumber;
assertEquals(positiveNumber, result);
Multiple expectations
then:
result == positiveNumber
!collection.isEmpty()
then:
result == positiveNumber
and:
!collection.isEmpty()
Multiple expectations
then:
result == positiveNumber
!collection.isEmpty()
then:
def expectedResult = positiveNumber
result == expectedResult
Only conditions and variable
assignments allowed
then:
result == positiveNumber
and:
!collection.isEmpty()
def "Crash if zero"() {
when:
object.crashIfZero(0)
then:
thrown(ZeroException)
}
@Test(expected = OperationException.class)
public void crashIfZero()
throws Exception {
object.crashIfZero(0);
}
Exception conditions
def "Crash if zero"() {
when:
object.crashIfZero(0)
then:
thrown(ZeroException)
}
@Test(expected = OperationException.class)
public void crashIfZero()
throws Exception {
object.crashIfZero(0);
}
def "Dont crash if not zero"() {
when:
object.crashIfZero(1)
then:
notThrown(ZeroException)
}
@Test // No exception should be thrown
public void dontCrashIfNotZero()
throws Exception {
object.crashIfZero(1);
}
Exception conditions
class KakaSpec extends Specification {
static final SUBSCRIPTION_ID = 27
private AuxiliarObject auxiliar
void setup() {
(...)
}
def "xxx"() {
(...)
}
}
public class XxxxxxxxxxTest {
private static final long SUBSCRIPTION_ID = 27;
private AuxiliarObject auxiliar;
@Before
public void setUp() throws Exception {
(...)
}
@Test
public void thatXxx() throws Exception {
(...)
}
}
The test class
Groovy syntax sugar
when:
def result = object.getRecords()
then:
result?.list == [1, 47, 23]
Optional types
Collection literals
No ; needed
== operator for equals
Safe navigation ?. operator
Improved error output
Condition not satisfied:
result.value == expectedResult
| | | |
| | | 12
| | false
| 10
PaymentResult(id=2,value=10)
02 MOCKING
Mocks Creation
@Mock
private CustomerDataRegistry customerRegistry;
(...)
private PaymentsCoordinator paymentCoordinator;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
paymentCoordinator = new PaymentsCoordinator(
customerRegistry, (...));
}
CustomerDataRegistry customerRegistry = Mock()
(...)
@Subject PaymentsCoordinator paymentCoordinator =
new PaymentsCoordinator(customerRegistry, (...))
Mocks Creation
@Mock
private CustomerDataRegistry customerRegistry;
(...)
private PaymentsCoordinator paymentCoordinator;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
paymentCoordinator = new PaymentsCoordinator(
customerRegistry, (...));
}
CustomerDataRegistry customerRegistry = Mock()
(...)
@Subject PaymentsCoordinator paymentCoordinator =
new PaymentsCoordinator(customerRegistry, (...))
Mocks Creation
@Mock
private CustomerDataRegistry customerRegistry;
(...)
private PaymentsCoordinator paymentCoordinator;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
paymentCoordinator = new PaymentsCoordinator(
customerRegistry, (...));
}
CustomerDataRegistry customerRegistry = Mock()
(...)
@Subject PaymentsCoordinator paymentCoordinator =
new PaymentsCoordinator(customerRegistry, (...))
Responses declaration
@Test
public void testSuccessfulPaymentWithNewCreditCard() throws Exception {
when(customerRegistry.getCustomerData(SUBSCRIPTION_ID)).thenReturn(CUSTOMER_DATA);
(...)
PaymentResult result = paymentCoordinator.doPayment(paymentData);
(...)
}
def "Succesful payment with new credit card"() {
given: "A registered customer"
customerRegistry.getCustomerData(SUBSCRIPTION_ID) >> CUSTOMER_DATA
(...)
when: "A payment is requested"
def result = paymentCoordinator.doPayment(paymentData)
(...)
}
Interaction expectations
@Test
public void testSuccessfulPaymentWithNewCreditCard() throws Exception {
(...)
when(paymentInteractor.performPaymentInProvider(inputFields))
.thenReturn(PAYMENT_SUCCESSFUL_OUTPUT);
PaymentResult result = paymentCoordinator.doPayment(paymentData);
verify(paymentInteractor).performPaymentInProvider(inputFields)).
(...)
}
def "Succesful payment with new credit card"() {
(...)
when: "A payment is requested"
def result = paymentCoordinator.doPayment(paymentData)
then: "It is sent to the payment provider with successful result"
1 * paymentInteractor.performPaymentInProvider(inputFields) >>
PAYMENT_SUCCESSFUL_OUTPUT
(...)
}
Mocks and Stubs
then:
0 * _
Semantic
Lenient: default
values
Only return values
Stubs: empty objects
Stubs: no interaction
expectations
Mocks: nulls
Call Matching
Arguments matching
mock.method("hello")
mock.method(!"hello")
mock.method()
mock.method(_)
mock.method(*_)
mock.method(_ as String)
mock.method({ l -> l.size() > 3 })
Method matching
customerRegistry._
_
customerRegistry./searchBy.*/(…)
Interactions expectations matching
Parametes matching
Order
1 * subscriber.receive("hello")
0 * subscriber.receive("hello")
(1..3) * subscriber.receive("hello")
(1.._) * subscriber.receive("hello")
(_..3) * subscriber.receive("hello")
_ * subscriber.receive("hello")
then:
1 * mock1.method1(...)
and:
1 * mock2.method2(...)
then:
1 * mock3.calledAfter1And2()
Cardinality * matching constraints
Forget the matchers
@Test
public void testSuccessfulPaymentWithNewCreditCard() throws Exception {
(...)
ArgumentMatcher<Payment> paymentMatcher = new ArgumentMatcher<Payment>() {
public boolean matches(Object payment) {
return ((Payment) payment).getPaymentType() != null;
}
};
verify(paymentInteractor, never()).performPaymentInProvider(
paymentMatcher, anyObject(), eq(VALIDATE));
(...)
}
def "Succesful payment with new credit card"() {
(...)
then:
0 * paymentInteractor.performPaymentInProvider(
{ payment -> payment.storedCard != null }, _, VALIDATE)
(...)
}
03 SOME
PRACTICAL USES
Property-based testing (JUnit parameterized tests)
@RunWith(Parameterized.class)
public class PaymentProcessingOfANewCompletedResponseAuthorizationHandlerTest {
public static Object[][] data() {
return new Object[][] {
{ TransactionStatus.INITIALIZED, TransactionStatus.AUTHORIZED },
{ TransactionStatus.INITIALIZED, TransactionStatus.REFUSED },
{ TransactionStatus.ACCEPTED, TransactionStatus.AUTHORIZED },
{ TransactionStatus.ACCEPTED, TransactionStatus.REFUSED }
};
}
@Parameter public TransactionStatus currentStatus;
@Parameter(value=1) public TransactionStatus responseStatus;
@Test
public void test() throws Exception {
(...)
}
}
Property-based testing (JUnit parameterized tests)
@RunWith(Parameterized.class)
public class PaymentProcessingOfANewCompletedResponseAuthorizationHandlerTest {
public static Object[][] data() {
return new Object[][] {
{ TransactionStatus.INITIALIZED, TransactionStatus.AUTHORIZED },
{ TransactionStatus.INITIALIZED, TransactionStatus.REFUSED },
{ TransactionStatus.ACCEPTED, TransactionStatus.AUTHORIZED },
{ TransactionStatus.ACCEPTED, TransactionStatus.REFUSED }
};
}
@Parameter public TransactionStatus currentStatus;
@Parameter(value=1) public TransactionStatus responseStatus;
@Test
public void test() throws Exception {
(...)
}
}
Property-based testing (JUnit parameterized tests)
@RunWith(Parameterized.class)
public class PaymentProcessingOfANewCompletedResponseAuthorizationHandlerTest {
public static Object[][] data() {
return new Object[][] {
{ TransactionStatus.INITIALIZED, TransactionStatus.AUTHORIZED },
{ TransactionStatus.INITIALIZED, TransactionStatus.REFUSED },
{ TransactionStatus.ACCEPTED, TransactionStatus.AUTHORIZED },
{ TransactionStatus.ACCEPTED, TransactionStatus.REFUSED }
};
}
@Parameter public TransactionStatus currentStatus;
@Parameter(value=1) public TransactionStatus responseStatus;
@Test
public void test() throws Exception {
(...)
}
}
Property-based testing (JUnit parameterized tests)
@RunWith(Parameterized.class)
public class PaymentProcessingOfANewCompletedResponseAuthorizationHandlerTest {
public static Object[][] data() {
return new Object[][] {
{ TransactionStatus.INITIALIZED, TransactionStatus.AUTHORIZED },
{ TransactionStatus.INITIALIZED, TransactionStatus.REFUSED },
{ TransactionStatus.ACCEPTED, TransactionStatus.AUTHORIZED },
{ TransactionStatus.ACCEPTED, TransactionStatus.REFUSED }
};
}
@Parameter public TransactionStatus currentStatus;
@Parameter(value=1) public TransactionStatus responseStatus;
@Test
public void test() throws Exception {
(...)
}
}
Property-based testing (Spock where)
@Unroll
def "Processing of a new completed response from status #currentStatus to #responseStatus"(
currentStatus, responseStatus) {
(...)
when:
def resultTransaction = authorizationHandler.processResponse(statusInfo, FROM_RETRY)
then:
(...)
where:
currentStatus | responseStatus
TransactionStatus.INITIALIZED | TransactionStatus.AUTHORIZED
TransactionStatus.INITIALIZED | TransactionStatus.REFUSED
TransactionStatus.ACCEPTED | TransactionStatus.AUTHORIZED
TransactionStatus.ACCEPTED | TransactionStatus.REFUSED
}
Property-based testing (Spock where)
@Unroll
def "Processing of a new completed response from status #currentStatus to #responseStatus"(
currentStatus, responseStatus) {
(...)
when:
def resultTransaction = authorizationHandler.processResponse(statusInfo, FROM_RETRY)
then:
(...)
where:
currentStatus | responseStatus
TransactionStatus.INITIALIZED | TransactionStatus.AUTHORIZED
TransactionStatus.INITIALIZED | TransactionStatus.REFUSED
TransactionStatus.ACCEPTED | TransactionStatus.AUTHORIZED
TransactionStatus.ACCEPTED | TransactionStatus.REFUSED
}
Config tests (multiline and String interpolation)
def "getRejectionReasonForError with invalid reason mapped"() {
given:
def yaml = """
paymentForm:
rejectionReasonMapping:
${ERROR_CODE}: '${REJECTION_REASON_INVALID}'
"""
def config = formConfig(yaml)
when:
def returnedReason = config.getRejectionReasonForError(ERROR_CODE)
then: "Returns general error"
returnedReason == PaymentRejectionReason.GENERAL_ERROR
}
Config tests (multiline and String interpolation)
def "getRejectionReasonForError with invalid reason mapped"() {
given:
def yaml = """
paymentForm:
rejectionReasonMapping:
${ERROR_CODE}: '${REJECTION_REASON_INVALID}'
"""
def config = formConfig(yaml)
when:
def returnedReason = config.getRejectionReasonForError(ERROR_CODE)
then: "Returns general error"
returnedReason == PaymentRejectionReason.GENERAL_ERROR
}
Builders?
def payment = new PaymentTransaction(
id: TRANSACTION_ID,
subscriptionId: SUBSCRIPTION_ID,
amount: AMOUNT,
lastChangeTimestamp: OLD_TIMESTAMP)
PaymentTransaction payment = new PaymentTransactionBuilder()
.id(TRANSACTION_ID)
.subscriptionId(SUBSCRIPTION_ID)
.amount(AMOUNT)
.lastChangeTimestamp(OLD_TIMESTAMP)
.build();
Default constructor with
named parameters
Builders?
def payment = new PaymentTransaction(
id: TRANSACTION_ID,
subscriptionId: SUBSCRIPTION_ID,
amount: AMOUNT,
lastChangeTimestamp: OLD_TIMESTAMP)
PaymentTransaction payment = new PaymentTransactionBuilder()
.id(TRANSACTION_ID)
.subscriptionId(SUBSCRIPTION_ID)
.amount(AMOUNT)
.lastChangeTimestamp(OLD_TIMESTAMP)
.build();
Default constructor with
named parameters
def "Process an authorized payment "() {
given: "An already authorized payment"
def authorizedPayment = paymentTransactionWith(status: TransactionStatus.AUTHORIZED)
(...)
}
private PaymentTransaction paymentTransactionWith(Map overrides) {
def attrs = [
id: TRANSACTION_ID,
subscriptionId: SUBSCRIPTION_ID,
amount: AMOUNT,
status: TransactionStatus.INITIALIZED,
lastChangeTimestamp: OLD_TIMESTAMP
] + overrides
return new PaymentTransaction(attrs)
}
Objects with default properties
def "Process an authorized payment "() {
given: "An already authorized payment"
def authorizedPayment = paymentTransactionWith(status: TransactionStatus.AUTHORIZED)
(...)
}
private PaymentTransaction paymentTransactionWith(Map overrides) {
def attrs = [
id: TRANSACTION_ID,
subscriptionId: SUBSCRIPTION_ID,
amount: AMOUNT,
status: TransactionStatus.INITIALIZED,
lastChangeTimestamp: OLD_TIMESTAMP
] + overrides
return new PaymentTransaction(attrs)
}
Objects with default properties
Private methods for readability?
PaymentTransaction transaction = givenAnAuthorizedTransaction();
paymentProcessor.processPayment(transaction, RESPONSE_DATA);
verifyTheTransactionIsTransitionedTo(ADDING_BALANCE);
verifyTheTopupIsProcessedCorrectly();
Private methods for readability?
given: "An already authorized transaction"
def transaction = transactionWith(status: AUTHORIZED)
transactionRegistry.getTransactionInfo(TRANSACTION_ID) >> transaction
when: "The payment is processed"
paymentProcessor.processPayment(transaction, RESPONSE_DATA)
then: "The transaction is transitioned to adding balance status"
1 * transactionRegistry.changeTransactionStatus(
TRANSACTION_ID, TransactionStatus.ADDING_BALANCE) >>
transactionWith(status: ADDING_BALANCE)
then: "The topup is processed"
1 * topupInteractor.topup(transaction, RESPONSE_DATA) >>
new PaymentStatusInfo(TRANSACTION_ID, TransactionStatus.BALANCE_ADDED)
PaymentTransaction transaction = givenAnAuthorizedTransaction();
paymentProcessor.processPayment(transaction, RESPONSE_DATA);
verifyTheTransactionIsTransitionedTo(ADDING_BALANCE);
verifyTheTopupIsProcessedCorrectly();
static final MERCADOPAGO_RESULT = [
status: 'approved',
status_detail: 'ok',
description: 'Tuenti (test)',
id: 999999,
authorization_code: 858,
collector_id: 5678,
statement_descriptor: 'WWW.MERCADOPAGO.COM',
card: [
last_four_digits: 1234,
expiration_year: 2016,
expiration_month: 12
],
payer: [
first_name: NAME,
last_name: LAST_NAME,
email: EMAIL,
]
]
Tests involving 3rd party APIs – Thank God for Collection
literals
04 So
what...?
●
Increase abstraction level
Not “programming tests” ® specify test cases
Easy + powerful
Expressivity ® test is also documentation
● Easy to run in continuous integration systems / IDEs
● Better error detection info
Advantages?
● Code Refactors not so safe
● Mocks can only be created in the Spec class
Integration tests with dependency injection overrides ... more
difficult, but possible!
Disadvantages?
● Code Refactors not so safe
● Mocks can only be created in the Spec class
Integration tests with dependency injection overrides ... more
difficult, but possible!
Disadvantages?
class BaseIntegrationSpecification extends TIntegrationSpecification {
@InjectOverride MercadopagoClient mercadopago = Mock()
@Inject PaymentNotificationsService paymentNotificationsServiceMock
(...)
@TIntegrationTestsModule
static class MockedBoundariesModule extends SpockMocksModule {
(...)
}
}
● Code Refactors not so safe
● Mocks can only be created in the Spec class
Integration tests with dependency injection overrides ... more
difficult, but possible!
Disadvantages?
class BaseIntegrationSpecification extends TIntegrationSpecification {
@InjectOverride MercadopagoClient mercadopago = Mock()
@Inject PaymentNotificationsService paymentNotificationsServiceMock
(...)
@TIntegrationTestsModule
static class MockedBoundariesModule extends SpockMocksModule {
(...)
}
}
Do you dare to change?
Do you dare to change?
Andrés ViedmaAndrés Viedma
@andres_viedma@andres_viedma
Questions?

Más contenido relacionado

La actualidad más candente

Pads lab manual final
Pads lab manual finalPads lab manual final
Pads lab manual finalAhalyaR
 
Program for hamming code using c
Program for hamming code using cProgram for hamming code using c
Program for hamming code using csnsanth
 
Oops lab manual2
Oops lab manual2Oops lab manual2
Oops lab manual2Mouna Guru
 
54602399 c-examples-51-to-108-programe-ee01083101
54602399 c-examples-51-to-108-programe-ee0108310154602399 c-examples-51-to-108-programe-ee01083101
54602399 c-examples-51-to-108-programe-ee01083101premrings
 
Travel management
Travel managementTravel management
Travel management1Parimal2
 
Alexey Tsoy Meta Programming in C++ 16.11.17
Alexey Tsoy Meta Programming in C++ 16.11.17Alexey Tsoy Meta Programming in C++ 16.11.17
Alexey Tsoy Meta Programming in C++ 16.11.17LogeekNightUkraine
 
(Rx).NET' way of async programming (.NET summit 2017 Belarus)
(Rx).NET' way of async programming (.NET summit 2017 Belarus)(Rx).NET' way of async programming (.NET summit 2017 Belarus)
(Rx).NET' way of async programming (.NET summit 2017 Belarus)Stas Rivkin
 
CBSE Class XII Comp sc practical file
CBSE Class XII Comp sc practical fileCBSE Class XII Comp sc practical file
CBSE Class XII Comp sc practical filePranav Ghildiyal
 
Ejercicios de programacion
Ejercicios de programacionEjercicios de programacion
Ejercicios de programacionJeff Tu Pechito
 
Обзор фреймворка Twisted
Обзор фреймворка TwistedОбзор фреймворка Twisted
Обзор фреймворка TwistedMaxim Kulsha
 

La actualidad más candente (20)

Exceptional exceptions
Exceptional exceptionsExceptional exceptions
Exceptional exceptions
 
Pads lab manual final
Pads lab manual finalPads lab manual final
Pads lab manual final
 
Program for hamming code using c
Program for hamming code using cProgram for hamming code using c
Program for hamming code using c
 
Oops lab manual2
Oops lab manual2Oops lab manual2
Oops lab manual2
 
C++ TUTORIAL 10
C++ TUTORIAL 10C++ TUTORIAL 10
C++ TUTORIAL 10
 
C++ TUTORIAL 6
C++ TUTORIAL 6C++ TUTORIAL 6
C++ TUTORIAL 6
 
54602399 c-examples-51-to-108-programe-ee01083101
54602399 c-examples-51-to-108-programe-ee0108310154602399 c-examples-51-to-108-programe-ee01083101
54602399 c-examples-51-to-108-programe-ee01083101
 
Travel management
Travel managementTravel management
Travel management
 
Cpp c++ 1
Cpp c++ 1Cpp c++ 1
Cpp c++ 1
 
Promise is a Promise
Promise is a PromisePromise is a Promise
Promise is a Promise
 
C++ file
C++ fileC++ file
C++ file
 
C programs
C programsC programs
C programs
 
Alexey Tsoy Meta Programming in C++ 16.11.17
Alexey Tsoy Meta Programming in C++ 16.11.17Alexey Tsoy Meta Programming in C++ 16.11.17
Alexey Tsoy Meta Programming in C++ 16.11.17
 
(Rx).NET' way of async programming (.NET summit 2017 Belarus)
(Rx).NET' way of async programming (.NET summit 2017 Belarus)(Rx).NET' way of async programming (.NET summit 2017 Belarus)
(Rx).NET' way of async programming (.NET summit 2017 Belarus)
 
CBSE Class XII Comp sc practical file
CBSE Class XII Comp sc practical fileCBSE Class XII Comp sc practical file
CBSE Class XII Comp sc practical file
 
Ejercicios de programacion
Ejercicios de programacionEjercicios de programacion
Ejercicios de programacion
 
Обзор фреймворка Twisted
Обзор фреймворка TwistedОбзор фреймворка Twisted
Обзор фреймворка Twisted
 
Static and const members
Static and const membersStatic and const members
Static and const members
 
C++ TUTORIAL 5
C++ TUTORIAL 5C++ TUTORIAL 5
C++ TUTORIAL 5
 
Pointers
PointersPointers
Pointers
 

Similar a Por qué usar Spock en lugar de JUnit / Mockito para tus tests Java - Codemotion 2016

Write a Java program in which a method named digitSum that accepts a.pdf
Write a Java program in which a method named digitSum that accepts a.pdfWrite a Java program in which a method named digitSum that accepts a.pdf
Write a Java program in which a method named digitSum that accepts a.pdfnaveenkumar29100
 
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...DevGAMM Conference
 
ES3-2020-07 Testing techniques
ES3-2020-07 Testing techniquesES3-2020-07 Testing techniques
ES3-2020-07 Testing techniquesDavid Rodenas
 
Adodb Scripts And Some Sample Scripts[1]
Adodb Scripts And Some Sample Scripts[1]Adodb Scripts And Some Sample Scripts[1]
Adodb Scripts And Some Sample Scripts[1]testduser1
 
Adodb Scripts And Some Sample Scripts[1]
Adodb Scripts And Some Sample Scripts[1]Adodb Scripts And Some Sample Scripts[1]
Adodb Scripts And Some Sample Scripts[1]User1test
 
Improving the java type system
Improving the java type systemImproving the java type system
Improving the java type systemJoão Loff
 
C++ code only(Retrieve of Malik D., 2015, p. 742) Programming Exer.pdf
C++ code only(Retrieve of Malik D., 2015, p. 742) Programming Exer.pdfC++ code only(Retrieve of Malik D., 2015, p. 742) Programming Exer.pdf
C++ code only(Retrieve of Malik D., 2015, p. 742) Programming Exer.pdfandreaplotner1
 
Classic Games Development with Drools
Classic Games Development with DroolsClassic Games Development with Drools
Classic Games Development with DroolsMark Proctor
 
Automatically Repairing Test Cases for Evolving Method Declarations
Automatically Repairing Test Cases for Evolving Method DeclarationsAutomatically Repairing Test Cases for Evolving Method Declarations
Automatically Repairing Test Cases for Evolving Method DeclarationsICSM 2010
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesAndrey Karpov
 
Rechecking SharpDevelop: Any New Bugs?
Rechecking SharpDevelop: Any New Bugs?Rechecking SharpDevelop: Any New Bugs?
Rechecking SharpDevelop: Any New Bugs?PVS-Studio
 
Unbearable Test Code Smell
Unbearable Test Code SmellUnbearable Test Code Smell
Unbearable Test Code SmellSteven Mak
 
Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8Frédéric Delorme
 
Test-driven Development (TDD)
Test-driven Development (TDD)Test-driven Development (TDD)
Test-driven Development (TDD)Bran van der Meer
 
Chainer-Compiler 動かしてみた
Chainer-Compiler 動かしてみたChainer-Compiler 動かしてみた
Chainer-Compiler 動かしてみたAkira Maruoka
 
Ensure code quality with vs2012
Ensure code quality with vs2012Ensure code quality with vs2012
Ensure code quality with vs2012Sandeep Joshi
 

Similar a Por qué usar Spock en lugar de JUnit / Mockito para tus tests Java - Codemotion 2016 (20)

Write a Java program in which a method named digitSum that accepts a.pdf
Write a Java program in which a method named digitSum that accepts a.pdfWrite a Java program in which a method named digitSum that accepts a.pdf
Write a Java program in which a method named digitSum that accepts a.pdf
 
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
 
ES3-2020-07 Testing techniques
ES3-2020-07 Testing techniquesES3-2020-07 Testing techniques
ES3-2020-07 Testing techniques
 
Adodb Scripts And Some Sample Scripts[1]
Adodb Scripts And Some Sample Scripts[1]Adodb Scripts And Some Sample Scripts[1]
Adodb Scripts And Some Sample Scripts[1]
 
Adodb Scripts And Some Sample Scripts[1]
Adodb Scripts And Some Sample Scripts[1]Adodb Scripts And Some Sample Scripts[1]
Adodb Scripts And Some Sample Scripts[1]
 
Developer Testing Tools Roundup
Developer Testing Tools RoundupDeveloper Testing Tools Roundup
Developer Testing Tools Roundup
 
Improving the java type system
Improving the java type systemImproving the java type system
Improving the java type system
 
A Test of Strength
A Test of StrengthA Test of Strength
A Test of Strength
 
C++ code only(Retrieve of Malik D., 2015, p. 742) Programming Exer.pdf
C++ code only(Retrieve of Malik D., 2015, p. 742) Programming Exer.pdfC++ code only(Retrieve of Malik D., 2015, p. 742) Programming Exer.pdf
C++ code only(Retrieve of Malik D., 2015, p. 742) Programming Exer.pdf
 
Classic Games Development with Drools
Classic Games Development with DroolsClassic Games Development with Drools
Classic Games Development with Drools
 
Automatically Repairing Test Cases for Evolving Method Declarations
Automatically Repairing Test Cases for Evolving Method DeclarationsAutomatically Repairing Test Cases for Evolving Method Declarations
Automatically Repairing Test Cases for Evolving Method Declarations
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
 
Rechecking SharpDevelop: Any New Bugs?
Rechecking SharpDevelop: Any New Bugs?Rechecking SharpDevelop: Any New Bugs?
Rechecking SharpDevelop: Any New Bugs?
 
Unbearable Test Code Smell
Unbearable Test Code SmellUnbearable Test Code Smell
Unbearable Test Code Smell
 
Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8
 
Test-driven Development (TDD)
Test-driven Development (TDD)Test-driven Development (TDD)
Test-driven Development (TDD)
 
Rhino Mocks
Rhino MocksRhino Mocks
Rhino Mocks
 
C programming
C programmingC programming
C programming
 
Chainer-Compiler 動かしてみた
Chainer-Compiler 動かしてみたChainer-Compiler 動かしてみた
Chainer-Compiler 動かしてみた
 
Ensure code quality with vs2012
Ensure code quality with vs2012Ensure code quality with vs2012
Ensure code quality with vs2012
 

Último

Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfproinshot.com
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024Mind IT Systems
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfVishalKumarJha10
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesVictorSzoltysek
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdfPearlKirahMaeRagusta1
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionOnePlan Solutions
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 

Último (20)

Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 

Por qué usar Spock en lugar de JUnit / Mockito para tus tests Java - Codemotion 2016

  • 1. MADRID · NOV 18-19 · 2016 Why Using by @andres_viedma instead of in your Java Tests
  • 4. A testing framework Tests are written in 100% compatible with Java code Runs on http://spockframework.org/
  • 5. A basic JUnit test @Test public void thatAddAPositiveNumberToZeroReturnsTheSamePositiveNumber() throws Exception { int positiveNumber = 23; int zero = 0; int result = zero + positiveNumber; assertEquals(positiveNumber, result); }
  • 6. A basic Spock test def "Add a positive number to zero returns the same positive number"() { given: def positiveNumber = 23 def zero = 0 when: def result = zero + positiveNumber then: result == positiveNumber }
  • 7. A basic Spock test def "Add a positive number to zero returns the same positive number"() { given: def positiveNumber = 23 def zero = 0 when: def result = zero + positiveNumber then: result == positiveNumber }
  • 8. A basic Spock test DSL def "Add a positive number to zero returns the same positive number"() { given: def positiveNumber = 23 def zero = 0 when: def result = zero + positiveNumber then: result == positiveNumber }
  • 9. String literals def "Add a positive number to zero returns the same positive number"() { (...) } @Test public void thatAddAPositiveNumberToZeroReturnsTheSamePositiveNumber() throws Exception { (...) }
  • 10. String literals def "Add a positive number to zero returns the same positive number"() { (...) } @Test public void thatAddAPositiveNumberToZeroReturnsTheSamePositiveNumber() throws Exception { (...) } def "En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga antigua, rocín flaco y galgo corredor. "() { (...) }
  • 11. Spock Blocks given: def positiveNumber = 23 def zero = 0 when: def result = zero + positiveNumber then: result == positiveNumber int positiveNumber = 23; int zero = 0; int result = zero + positiveNumber; assertEquals(positiveNumber, result); Programming vs. Specification
  • 12. Spock Blocks given: def positiveNumber = 23 def zero = 0 when: def result = zero + positiveNumber then: result == positiveNumber // Given int positiveNumber = 23; int zero = 0; // When int result = zero + positiveNumber; // Then assertEquals(positiveNumber, result); Compilation check Programming vs. Specification
  • 13. Documented Spock Blocks given: "A positive number" def positiveNumber = 23 and: "Well... a SPECTACULAR zero" def zero = 0 when: "The number is added to zero" def result = zero + positiveNumber then: "The result is the same number" result == positiveNumber int positiveNumber = 23; int zero = 0; int result = zero + positiveNumber; assertEquals(positiveNumber, result); Documents purpose Helps thinking
  • 14. expect block given: "A positive number" def positiveNumber = 23 expect: "That added to zero results the same number" zero + positiveNumber == positiveNumber Replaces when-then for simple functional tests
  • 15. Expectations (then / expect) given: def positiveNumber = 23 def zero = 0 when: def result = zero + positiveNumber then: result == positiveNumber int positiveNumber = 23; int zero = 0; int result = zero + positiveNumber; assertEquals(positiveNumber, result);
  • 16. Multiple expectations then: result == positiveNumber !collection.isEmpty() then: result == positiveNumber and: !collection.isEmpty()
  • 17. Multiple expectations then: result == positiveNumber !collection.isEmpty() then: def expectedResult = positiveNumber result == expectedResult Only conditions and variable assignments allowed then: result == positiveNumber and: !collection.isEmpty()
  • 18. def "Crash if zero"() { when: object.crashIfZero(0) then: thrown(ZeroException) } @Test(expected = OperationException.class) public void crashIfZero() throws Exception { object.crashIfZero(0); } Exception conditions
  • 19. def "Crash if zero"() { when: object.crashIfZero(0) then: thrown(ZeroException) } @Test(expected = OperationException.class) public void crashIfZero() throws Exception { object.crashIfZero(0); } def "Dont crash if not zero"() { when: object.crashIfZero(1) then: notThrown(ZeroException) } @Test // No exception should be thrown public void dontCrashIfNotZero() throws Exception { object.crashIfZero(1); } Exception conditions
  • 20. class KakaSpec extends Specification { static final SUBSCRIPTION_ID = 27 private AuxiliarObject auxiliar void setup() { (...) } def "xxx"() { (...) } } public class XxxxxxxxxxTest { private static final long SUBSCRIPTION_ID = 27; private AuxiliarObject auxiliar; @Before public void setUp() throws Exception { (...) } @Test public void thatXxx() throws Exception { (...) } } The test class
  • 21. Groovy syntax sugar when: def result = object.getRecords() then: result?.list == [1, 47, 23] Optional types Collection literals No ; needed == operator for equals Safe navigation ?. operator
  • 22. Improved error output Condition not satisfied: result.value == expectedResult | | | | | | | 12 | | false | 10 PaymentResult(id=2,value=10)
  • 24. Mocks Creation @Mock private CustomerDataRegistry customerRegistry; (...) private PaymentsCoordinator paymentCoordinator; @Before public void setup() { MockitoAnnotations.initMocks(this); paymentCoordinator = new PaymentsCoordinator( customerRegistry, (...)); } CustomerDataRegistry customerRegistry = Mock() (...) @Subject PaymentsCoordinator paymentCoordinator = new PaymentsCoordinator(customerRegistry, (...))
  • 25. Mocks Creation @Mock private CustomerDataRegistry customerRegistry; (...) private PaymentsCoordinator paymentCoordinator; @Before public void setup() { MockitoAnnotations.initMocks(this); paymentCoordinator = new PaymentsCoordinator( customerRegistry, (...)); } CustomerDataRegistry customerRegistry = Mock() (...) @Subject PaymentsCoordinator paymentCoordinator = new PaymentsCoordinator(customerRegistry, (...))
  • 26. Mocks Creation @Mock private CustomerDataRegistry customerRegistry; (...) private PaymentsCoordinator paymentCoordinator; @Before public void setup() { MockitoAnnotations.initMocks(this); paymentCoordinator = new PaymentsCoordinator( customerRegistry, (...)); } CustomerDataRegistry customerRegistry = Mock() (...) @Subject PaymentsCoordinator paymentCoordinator = new PaymentsCoordinator(customerRegistry, (...))
  • 27. Responses declaration @Test public void testSuccessfulPaymentWithNewCreditCard() throws Exception { when(customerRegistry.getCustomerData(SUBSCRIPTION_ID)).thenReturn(CUSTOMER_DATA); (...) PaymentResult result = paymentCoordinator.doPayment(paymentData); (...) } def "Succesful payment with new credit card"() { given: "A registered customer" customerRegistry.getCustomerData(SUBSCRIPTION_ID) >> CUSTOMER_DATA (...) when: "A payment is requested" def result = paymentCoordinator.doPayment(paymentData) (...) }
  • 28. Interaction expectations @Test public void testSuccessfulPaymentWithNewCreditCard() throws Exception { (...) when(paymentInteractor.performPaymentInProvider(inputFields)) .thenReturn(PAYMENT_SUCCESSFUL_OUTPUT); PaymentResult result = paymentCoordinator.doPayment(paymentData); verify(paymentInteractor).performPaymentInProvider(inputFields)). (...) } def "Succesful payment with new credit card"() { (...) when: "A payment is requested" def result = paymentCoordinator.doPayment(paymentData) then: "It is sent to the payment provider with successful result" 1 * paymentInteractor.performPaymentInProvider(inputFields) >> PAYMENT_SUCCESSFUL_OUTPUT (...) }
  • 29. Mocks and Stubs then: 0 * _ Semantic Lenient: default values Only return values Stubs: empty objects Stubs: no interaction expectations Mocks: nulls
  • 30. Call Matching Arguments matching mock.method("hello") mock.method(!"hello") mock.method() mock.method(_) mock.method(*_) mock.method(_ as String) mock.method({ l -> l.size() > 3 }) Method matching customerRegistry._ _ customerRegistry./searchBy.*/(…)
  • 31. Interactions expectations matching Parametes matching Order 1 * subscriber.receive("hello") 0 * subscriber.receive("hello") (1..3) * subscriber.receive("hello") (1.._) * subscriber.receive("hello") (_..3) * subscriber.receive("hello") _ * subscriber.receive("hello") then: 1 * mock1.method1(...) and: 1 * mock2.method2(...) then: 1 * mock3.calledAfter1And2() Cardinality * matching constraints
  • 32. Forget the matchers @Test public void testSuccessfulPaymentWithNewCreditCard() throws Exception { (...) ArgumentMatcher<Payment> paymentMatcher = new ArgumentMatcher<Payment>() { public boolean matches(Object payment) { return ((Payment) payment).getPaymentType() != null; } }; verify(paymentInteractor, never()).performPaymentInProvider( paymentMatcher, anyObject(), eq(VALIDATE)); (...) } def "Succesful payment with new credit card"() { (...) then: 0 * paymentInteractor.performPaymentInProvider( { payment -> payment.storedCard != null }, _, VALIDATE) (...) }
  • 34. Property-based testing (JUnit parameterized tests) @RunWith(Parameterized.class) public class PaymentProcessingOfANewCompletedResponseAuthorizationHandlerTest { public static Object[][] data() { return new Object[][] { { TransactionStatus.INITIALIZED, TransactionStatus.AUTHORIZED }, { TransactionStatus.INITIALIZED, TransactionStatus.REFUSED }, { TransactionStatus.ACCEPTED, TransactionStatus.AUTHORIZED }, { TransactionStatus.ACCEPTED, TransactionStatus.REFUSED } }; } @Parameter public TransactionStatus currentStatus; @Parameter(value=1) public TransactionStatus responseStatus; @Test public void test() throws Exception { (...) } }
  • 35. Property-based testing (JUnit parameterized tests) @RunWith(Parameterized.class) public class PaymentProcessingOfANewCompletedResponseAuthorizationHandlerTest { public static Object[][] data() { return new Object[][] { { TransactionStatus.INITIALIZED, TransactionStatus.AUTHORIZED }, { TransactionStatus.INITIALIZED, TransactionStatus.REFUSED }, { TransactionStatus.ACCEPTED, TransactionStatus.AUTHORIZED }, { TransactionStatus.ACCEPTED, TransactionStatus.REFUSED } }; } @Parameter public TransactionStatus currentStatus; @Parameter(value=1) public TransactionStatus responseStatus; @Test public void test() throws Exception { (...) } }
  • 36. Property-based testing (JUnit parameterized tests) @RunWith(Parameterized.class) public class PaymentProcessingOfANewCompletedResponseAuthorizationHandlerTest { public static Object[][] data() { return new Object[][] { { TransactionStatus.INITIALIZED, TransactionStatus.AUTHORIZED }, { TransactionStatus.INITIALIZED, TransactionStatus.REFUSED }, { TransactionStatus.ACCEPTED, TransactionStatus.AUTHORIZED }, { TransactionStatus.ACCEPTED, TransactionStatus.REFUSED } }; } @Parameter public TransactionStatus currentStatus; @Parameter(value=1) public TransactionStatus responseStatus; @Test public void test() throws Exception { (...) } }
  • 37. Property-based testing (JUnit parameterized tests) @RunWith(Parameterized.class) public class PaymentProcessingOfANewCompletedResponseAuthorizationHandlerTest { public static Object[][] data() { return new Object[][] { { TransactionStatus.INITIALIZED, TransactionStatus.AUTHORIZED }, { TransactionStatus.INITIALIZED, TransactionStatus.REFUSED }, { TransactionStatus.ACCEPTED, TransactionStatus.AUTHORIZED }, { TransactionStatus.ACCEPTED, TransactionStatus.REFUSED } }; } @Parameter public TransactionStatus currentStatus; @Parameter(value=1) public TransactionStatus responseStatus; @Test public void test() throws Exception { (...) } }
  • 38. Property-based testing (Spock where) @Unroll def "Processing of a new completed response from status #currentStatus to #responseStatus"( currentStatus, responseStatus) { (...) when: def resultTransaction = authorizationHandler.processResponse(statusInfo, FROM_RETRY) then: (...) where: currentStatus | responseStatus TransactionStatus.INITIALIZED | TransactionStatus.AUTHORIZED TransactionStatus.INITIALIZED | TransactionStatus.REFUSED TransactionStatus.ACCEPTED | TransactionStatus.AUTHORIZED TransactionStatus.ACCEPTED | TransactionStatus.REFUSED }
  • 39. Property-based testing (Spock where) @Unroll def "Processing of a new completed response from status #currentStatus to #responseStatus"( currentStatus, responseStatus) { (...) when: def resultTransaction = authorizationHandler.processResponse(statusInfo, FROM_RETRY) then: (...) where: currentStatus | responseStatus TransactionStatus.INITIALIZED | TransactionStatus.AUTHORIZED TransactionStatus.INITIALIZED | TransactionStatus.REFUSED TransactionStatus.ACCEPTED | TransactionStatus.AUTHORIZED TransactionStatus.ACCEPTED | TransactionStatus.REFUSED }
  • 40. Config tests (multiline and String interpolation) def "getRejectionReasonForError with invalid reason mapped"() { given: def yaml = """ paymentForm: rejectionReasonMapping: ${ERROR_CODE}: '${REJECTION_REASON_INVALID}' """ def config = formConfig(yaml) when: def returnedReason = config.getRejectionReasonForError(ERROR_CODE) then: "Returns general error" returnedReason == PaymentRejectionReason.GENERAL_ERROR }
  • 41. Config tests (multiline and String interpolation) def "getRejectionReasonForError with invalid reason mapped"() { given: def yaml = """ paymentForm: rejectionReasonMapping: ${ERROR_CODE}: '${REJECTION_REASON_INVALID}' """ def config = formConfig(yaml) when: def returnedReason = config.getRejectionReasonForError(ERROR_CODE) then: "Returns general error" returnedReason == PaymentRejectionReason.GENERAL_ERROR }
  • 42. Builders? def payment = new PaymentTransaction( id: TRANSACTION_ID, subscriptionId: SUBSCRIPTION_ID, amount: AMOUNT, lastChangeTimestamp: OLD_TIMESTAMP) PaymentTransaction payment = new PaymentTransactionBuilder() .id(TRANSACTION_ID) .subscriptionId(SUBSCRIPTION_ID) .amount(AMOUNT) .lastChangeTimestamp(OLD_TIMESTAMP) .build(); Default constructor with named parameters
  • 43. Builders? def payment = new PaymentTransaction( id: TRANSACTION_ID, subscriptionId: SUBSCRIPTION_ID, amount: AMOUNT, lastChangeTimestamp: OLD_TIMESTAMP) PaymentTransaction payment = new PaymentTransactionBuilder() .id(TRANSACTION_ID) .subscriptionId(SUBSCRIPTION_ID) .amount(AMOUNT) .lastChangeTimestamp(OLD_TIMESTAMP) .build(); Default constructor with named parameters
  • 44. def "Process an authorized payment "() { given: "An already authorized payment" def authorizedPayment = paymentTransactionWith(status: TransactionStatus.AUTHORIZED) (...) } private PaymentTransaction paymentTransactionWith(Map overrides) { def attrs = [ id: TRANSACTION_ID, subscriptionId: SUBSCRIPTION_ID, amount: AMOUNT, status: TransactionStatus.INITIALIZED, lastChangeTimestamp: OLD_TIMESTAMP ] + overrides return new PaymentTransaction(attrs) } Objects with default properties
  • 45. def "Process an authorized payment "() { given: "An already authorized payment" def authorizedPayment = paymentTransactionWith(status: TransactionStatus.AUTHORIZED) (...) } private PaymentTransaction paymentTransactionWith(Map overrides) { def attrs = [ id: TRANSACTION_ID, subscriptionId: SUBSCRIPTION_ID, amount: AMOUNT, status: TransactionStatus.INITIALIZED, lastChangeTimestamp: OLD_TIMESTAMP ] + overrides return new PaymentTransaction(attrs) } Objects with default properties
  • 46. Private methods for readability? PaymentTransaction transaction = givenAnAuthorizedTransaction(); paymentProcessor.processPayment(transaction, RESPONSE_DATA); verifyTheTransactionIsTransitionedTo(ADDING_BALANCE); verifyTheTopupIsProcessedCorrectly();
  • 47. Private methods for readability? given: "An already authorized transaction" def transaction = transactionWith(status: AUTHORIZED) transactionRegistry.getTransactionInfo(TRANSACTION_ID) >> transaction when: "The payment is processed" paymentProcessor.processPayment(transaction, RESPONSE_DATA) then: "The transaction is transitioned to adding balance status" 1 * transactionRegistry.changeTransactionStatus( TRANSACTION_ID, TransactionStatus.ADDING_BALANCE) >> transactionWith(status: ADDING_BALANCE) then: "The topup is processed" 1 * topupInteractor.topup(transaction, RESPONSE_DATA) >> new PaymentStatusInfo(TRANSACTION_ID, TransactionStatus.BALANCE_ADDED) PaymentTransaction transaction = givenAnAuthorizedTransaction(); paymentProcessor.processPayment(transaction, RESPONSE_DATA); verifyTheTransactionIsTransitionedTo(ADDING_BALANCE); verifyTheTopupIsProcessedCorrectly();
  • 48. static final MERCADOPAGO_RESULT = [ status: 'approved', status_detail: 'ok', description: 'Tuenti (test)', id: 999999, authorization_code: 858, collector_id: 5678, statement_descriptor: 'WWW.MERCADOPAGO.COM', card: [ last_four_digits: 1234, expiration_year: 2016, expiration_month: 12 ], payer: [ first_name: NAME, last_name: LAST_NAME, email: EMAIL, ] ] Tests involving 3rd party APIs – Thank God for Collection literals
  • 50. ● Increase abstraction level Not “programming tests” ® specify test cases Easy + powerful Expressivity ® test is also documentation ● Easy to run in continuous integration systems / IDEs ● Better error detection info Advantages?
  • 51. ● Code Refactors not so safe ● Mocks can only be created in the Spec class Integration tests with dependency injection overrides ... more difficult, but possible! Disadvantages?
  • 52. ● Code Refactors not so safe ● Mocks can only be created in the Spec class Integration tests with dependency injection overrides ... more difficult, but possible! Disadvantages? class BaseIntegrationSpecification extends TIntegrationSpecification { @InjectOverride MercadopagoClient mercadopago = Mock() @Inject PaymentNotificationsService paymentNotificationsServiceMock (...) @TIntegrationTestsModule static class MockedBoundariesModule extends SpockMocksModule { (...) } }
  • 53. ● Code Refactors not so safe ● Mocks can only be created in the Spec class Integration tests with dependency injection overrides ... more difficult, but possible! Disadvantages? class BaseIntegrationSpecification extends TIntegrationSpecification { @InjectOverride MercadopagoClient mercadopago = Mock() @Inject PaymentNotificationsService paymentNotificationsServiceMock (...) @TIntegrationTestsModule static class MockedBoundariesModule extends SpockMocksModule { (...) } }
  • 54. Do you dare to change?
  • 55. Do you dare to change?

Notas del editor

  1. Buenas a todos, gracias por venir. Java Testing ==&amp;gt; cuánta gente realmente prueba?
  2. - opensource, std. Groovy
  3. Fácil pensar – no te da tanto, ¿por qué cambiar? Ejemplo parecido – salto de altura Dick Fosbury – Mexico 68 Hasta años después no se popularizó del todo – quizá lo que pensaban entonces el resto de saltadores es que no te da tanto, que por qué cambiar, que ellos llevaban toooda la vida … saltando así.