Resistance is futile mocks will be assimilated

Post on 10-May-2015

4,508 views 0 download

Tags:

description

Conference given at Codemotion Madrid 2013 about writing tests not only using mocks.

transcript

asotobu@gmail.com - Everis

Alex Soto

Resistance is Futile, Mocks Will be Assimilated

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Mocks ?

Mocks are objects pre-programmed with expectations

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Mocks ?

Mocks are objects pre-programmed with expectations

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Mocks ?

Fast

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Mocks ?

Fast

Interface

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Mocks ?

Fast

Interface

70% Test Code

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Mocks ?

Fast

Interface

70% Test Code

Hard to Maintain

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Mocks ?

Fast

Interface

70% Test Code

Hard to Maintain

Container services

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Mocks ?

Fast

Interface

70% Test Code

Hard to Maintain

Container services

Uncertainty

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Mocks ?

Fast

Interface

70% Test Code

Hard to Maintain

Container services

Uncertainty

Duplication

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Mocks ?Kno

w Your

Enem

y?

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Java EE Scenario

Client Protocol

{text/html}

{app/json}{app/xml}

Server External

{app/json}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

High Level Tests

We D

on’t H

ave Tim

e

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Low Level Tests

State Of The Union

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

Mock DAOs

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

Mock DAOs

Fast

Isolated

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

Mock DAOs

Fast

Isolated

ORM Mapping

ORM Configuration

Queries

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

Fast

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

Fast

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

Fast

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

Isolated

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

Isolated

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

Isolated

Define base data set

CLEAN

INSERT

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

{! "Book":! ! ! [! ! ! ! {"title":"The Hobbit","numberOfPages":293}! ! ! ]}

@Rulepublic MongoDbRule remoteMongoDbRule = newMongoDbRule().defaultManagedMongoDb("db");

@Test@UsingDataSet(locations="data.json",loadStrategy=LoadStrategyEnum.CLEAN_INSERT)@ShouldMatchDataSet(location="expectedData.json")public void book_should_be_inserted_into_repository() {

//test}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

{! "Book":! ! ! [! ! ! ! {"title":"The Hobbit","numberOfPages":293}! ! ! ]}

@Rulepublic MongoDbRule remoteMongoDbRule = newMongoDbRule().defaultManagedMongoDb("db");

@Test@UsingDataSet(locations="data.json",loadStrategy=LoadStrategyEnum.CLEAN_INSERT)@ShouldMatchDataSet(location="expectedData.json")public void book_should_be_inserted_into_repository() {

//test}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

{! "Book":! ! ! [! ! ! ! {"title":"The Hobbit","numberOfPages":293}! ! ! ]}

@Rulepublic MongoDbRule remoteMongoDbRule = newMongoDbRule().defaultManagedMongoDb("db");

@Test@UsingDataSet(locations="data.json",loadStrategy=LoadStrategyEnum.CLEAN_INSERT)@ShouldMatchDataSet(location="expectedData.json")public void book_should_be_inserted_into_repository() {

//test}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Data Layer

{! "Book":! ! ! [! ! ! ! {"title":"The Hobbit","numberOfPages":293}! ! ! ]}

@Rulepublic MongoDbRule remoteMongoDbRule = newMongoDbRule().defaultManagedMongoDb("db");

@Test@UsingDataSet(locations="data.json",loadStrategy=LoadStrategyEnum.CLEAN_INSERT)@ShouldMatchDataSet(location="expectedData.json")public void book_should_be_inserted_into_repository() {

//test}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

E-mail

Mock E-mail access

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

E-mail

Mock E-mail access

Fast

Offline

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

E-mail

Mock E-mail access

Fast

Offline

javax.mail

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

E-mail

SMTPMailService.sendMail(MailMessageBuilder$MailMessage) Transport.send(Message) Transport.send0(Message, Address[]) SMTPTransport.sendMessage(Message, Address[]) MimeMessage.writeTo(OutputStream, String[]) MimeBodyPart.writeTo(MimePart, OutputStream, String[])

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

E-mail

Embeddable SMTP server

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

E-mail

private static final int SMTP_PORT = 2500;private static Wiser mailServer = new Wiser();

@BeforeClasspublic static void startWiser() {! mailServer.setPort(SMTP_PORT);! mailServer.start();}

@AfterClasspublic static void stopWiser() {! mailServer.stop();}

@Testpublic void an_email_should_be_sent() throws MessagingException, IOException {

! MailMessage message = mail().from("me@mail.com").addTo("you@mail.com")! ! ! ! .contentType("text/plain").subject("Welcome")! ! ! ! .body("Welcome to our site, thanks for registering on it.")! ! ! ! .build();

! SMTPMailService smtpMailService = getMailService();! smtpMailService.sendMail(message);

! WiserMessage sentMessage = getSentMessage();! !! String subject = sentMessage.getMimeMessage().getSubject();! assertThat(subject, is("Welcome"));! !}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

E-mail

private static final int SMTP_PORT = 2500;private static Wiser mailServer = new Wiser();

@BeforeClasspublic static void startWiser() {! mailServer.setPort(SMTP_PORT);! mailServer.start();}

@AfterClasspublic static void stopWiser() {! mailServer.stop();}

@Testpublic void an_email_should_be_sent() throws MessagingException, IOException {

! MailMessage message = mail().from("me@mail.com").addTo("you@mail.com")! ! ! ! .contentType("text/plain").subject("Welcome")! ! ! ! .body("Welcome to our site, thanks for registering on it.")! ! ! ! .build();

! SMTPMailService smtpMailService = getMailService();! smtpMailService.sendMail(message);

! WiserMessage sentMessage = getSentMessage();! !! String subject = sentMessage.getMimeMessage().getSubject();! assertThat(subject, is("Welcome"));! !}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

E-mail

private static final int SMTP_PORT = 2500;private static Wiser mailServer = new Wiser();

@BeforeClasspublic static void startWiser() {! mailServer.setPort(SMTP_PORT);! mailServer.start();}

@AfterClasspublic static void stopWiser() {! mailServer.stop();}

@Testpublic void an_email_should_be_sent() throws MessagingException, IOException {

! MailMessage message = mail().from("me@mail.com").addTo("you@mail.com")! ! ! ! .contentType("text/plain").subject("Welcome")! ! ! ! .body("Welcome to our site, thanks for registering on it.")! ! ! ! .build();

! SMTPMailService smtpMailService = getMailService();! smtpMailService.sendMail(message);

! WiserMessage sentMessage = getSentMessage();! !! String subject = sentMessage.getMimeMessage().getSubject();! assertThat(subject, is("Welcome"));! !}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

E-mail

private static final int SMTP_PORT = 2500;private static Wiser mailServer = new Wiser();

@BeforeClasspublic static void startWiser() {! mailServer.setPort(SMTP_PORT);! mailServer.start();}

@AfterClasspublic static void stopWiser() {! mailServer.stop();}

@Testpublic void an_email_should_be_sent() throws MessagingException, IOException {

! MailMessage message = mail().from("me@mail.com").addTo("you@mail.com")! ! ! ! .contentType("text/plain").subject("Welcome")! ! ! ! .body("Welcome to our site, thanks for registering on it.")! ! ! ! .build();

! SMTPMailService smtpMailService = getMailService();! smtpMailService.sendMail(message);

! WiserMessage sentMessage = getSentMessage();! !! String subject = sentMessage.getMimeMessage().getSubject();! assertThat(subject, is("Welcome"));! !}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

REST

Mock REST access

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

REST

Mock REST access

Fast

Offline

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

REST

Mock REST access

Fast

Offline

Full Call Stack

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

REST

Stubbing Web Services

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

REST

private static final String URL = "http://localhost:8089";

@Rulepublic WireMockRule wireMockRule = new WireMockRule(8089);!@Testpublic void issues_from_project_should_be_retrieved() {! !! givenThat(get(urlEqualTo("/repos/lordofthejars/nosqlunit/issues"))! ! .willReturn(aResponse() .withHeader("Content-Type", "application/json") .withBody(GET_RESPONSE_JSON))! );! !! GithubClient githubClient = new GithubClient(URL);! !! String issues = githubClient.invokeGetMethod("/repos/lordofthejars/nosqlunit/issues");

! //could be an object assertThat(issues, is(GET_RESPONSE_JSON));! !}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

REST

private static final String URL = "http://localhost:8089";

@Rulepublic WireMockRule wireMockRule = new WireMockRule(8089);!@Testpublic void issues_from_project_should_be_retrieved() {! !! givenThat(get(urlEqualTo("/repos/lordofthejars/nosqlunit/issues"))! ! .willReturn(aResponse() .withHeader("Content-Type", "application/json") .withBody(GET_RESPONSE_JSON))! );! !! GithubClient githubClient = new GithubClient(URL);! !! String issues = githubClient.invokeGetMethod("/repos/lordofthejars/nosqlunit/issues");

! //could be an object assertThat(issues, is(GET_RESPONSE_JSON));! !}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

REST

private static final String URL = "http://localhost:8089";

@Rulepublic WireMockRule wireMockRule = new WireMockRule(8089);!@Testpublic void issues_from_project_should_be_retrieved() {! !! givenThat(get(urlEqualTo("/repos/lordofthejars/nosqlunit/issues"))! ! .willReturn(aResponse() .withHeader("Content-Type", "application/json") .withBody(GET_RESPONSE_JSON))! );! !! GithubClient githubClient = new GithubClient(URL);! !! String issues = githubClient.invokeGetMethod("/repos/lordofthejars/nosqlunit/issues");

! //could be an object assertThat(issues, is(GET_RESPONSE_JSON));! !}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

REST

private static final String URL = "http://localhost:8089";

@Rulepublic WireMockRule wireMockRule = new WireMockRule(8089);!@Testpublic void issues_from_project_should_be_retrieved() {! !! givenThat(get(urlEqualTo("/repos/lordofthejars/nosqlunit/issues"))! ! .willReturn(aResponse() .withHeader("Content-Type", "application/json") .withBody(GET_RESPONSE_JSON))! );! !! GithubClient githubClient = new GithubClient(URL);! !! String issues = githubClient.invokeGetMethod("/repos/lordofthejars/nosqlunit/issues");

! //could be an object assertThat(issues, is(GET_RESPONSE_JSON));! !}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

Code Runs in Container

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

Code Runs in Container

CDI (Qualifiers, Produces, Alternatives, Decorators)

JPA (EntityManager, Transactions, Mapping)

Security

JSF (Conversation Scope, Binding, Validation)

JAX-RS, JAX-WS, ...

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

public class PaymentGateway {

@Inject @CreditCard PaymentProcessor paymentProcessor//...public void setPaymentProcessor(PaymentProcessor paymentProcessor) {...}

}

Are you sure it works?

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

Brings tests to runtime

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

Brings tests to runtime

Manage Lifecycle of Container

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

Brings tests to runtime

Manage Lifecycle of Container

Create/Deploy MicroDeployments

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

Brings tests to runtime

Manage Lifecycle of Container

Create/Deploy MicroDeployments

Enriching Test Classes

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

Brings tests to runtime

Manage Lifecycle of Container

Create/Deploy MicroDeployments

Enriching Test Classes

Run Tests Inside/Against Container

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

Brings tests to runtime

Manage Lifecycle of Container

Create/Deploy MicroDeployments

Enriching Test Classes

Run Tests Inside/Against Container

IDE Friendly

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Alex Soto

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Container

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobSpeaker’s name

Slide’s title

Let’s see in Action

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

UI

UI code

DOM Manipulation

Ajax

Widgets

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

UI

Drives the browser

Access web elements

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

UI

driver.get(contextPath.toString()+"login.xhtml");! !WebElement username = driver.findElement(By.id("username"));WebElement password = driver.findElement(By.id("password"));WebElement submit = driver.findElement(By.id("submit"));! !username.sendKeys("aa");password.sendKeys("bb");! !submit.click();! !WebElement welcomeMessage = driver.findElement(By.id("welcomeMessage"));

assertThat(welcomeMessage.getText(), is("Welcome"));

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

UI

driver.get(contextPath.toString()+"login.xhtml");! !WebElement username = driver.findElement(By.id("username"));WebElement password = driver.findElement(By.id("password"));WebElement submit = driver.findElement(By.id("submit"));! !username.sendKeys("aa");password.sendKeys("bb");! !submit.click();! !WebElement welcomeMessage = driver.findElement(By.id("welcomeMessage"));

assertThat(welcomeMessage.getText(), is("Welcome"));

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

UI

Arquillian Drone/Graphene

Sexy WebDriver API

Ajax-enabled

PageObjects

JQuery selectors

Call Javascript as Java

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

UI

Let’s see in Action

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Faults

Mock Fauls

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Faults

Mock Fauls

Race Conditions

Uncommon Exceptions

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Faults

Mock Fauls

Race Conditions

Uncommon Exceptions

Test Until Last Line

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Faults

Fault Injection

Modify Bytecode

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Faults

@Test(expected = ”IOException.class”)@BMRule(! ! name="throw IOException writting content",! ! targetClass = "com.lordofthejars.byteman.util.FileUtils",! ! targetMethod = "createFileWithContent",! ! targetLocation = "CALL BufferedWriter.write(String)",! ! action = "throw new java.io.IOException()"! ! )public void an_exception_should_be_thrown() throws IOException {! !! BackupManager backupManager = createBackupManager();! !! backupManager.backupData("Hello World");! !}

public void createFileWithContent(File filename, String content) throws IOException {

! ! ! BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);! ! ! bufferedWriter.write(content);}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Faults

@Test(expected = ”IOException.class”)@BMRule(! ! name="throw IOException writting content",! ! targetClass = "com.lordofthejars.byteman.util.FileUtils",! ! targetMethod = "createFileWithContent",! ! targetLocation = "CALL BufferedWriter.write(String)",! ! action = "throw new java.io.IOException()"! ! )public void an_exception_should_be_thrown() throws IOException {! !! BackupManager backupManager = createBackupManager();! !! backupManager.backupData("Hello World");! !}

public void createFileWithContent(File filename, String content) throws IOException {

! ! ! BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);! ! ! bufferedWriter.write(content);}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Faults

@Test(expected = ”IOException.class”)@BMRule(! ! name="throw IOException writting content",! ! targetClass = "com.lordofthejars.byteman.util.FileUtils",! ! targetMethod = "createFileWithContent",! ! targetLocation = "CALL BufferedWriter.write(String)",! ! action = "throw new java.io.IOException()"! ! )public void an_exception_should_be_thrown() throws IOException {! !! BackupManager backupManager = createBackupManager();! !! backupManager.backupData("Hello World");! !}

public void createFileWithContent(File filename, String content) throws IOException {

! ! ! BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);! ! ! bufferedWriter.write(content);}

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Continuous Integration/Delivery

Continuous Integration / Delivery

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Continuous Integration/Delivery

Continuous Integration / Delivery

Commit Stage

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Continuous Integration/Delivery

Continuous Integration / Delivery

Commit Stage

Mock Expensive Operations

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Continuous Integration/Delivery

Continuous Integration / Delivery

Commit Stage

Mock Expensive Operations

Monitor Tests

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Continuous Integration/Delivery

Continuous Integration / Delivery

Commit Stage

Mock Expensive Operations

Monitor Tests

Bye Bye Uncertainty

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Recap

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Recap

Mock is an option, not a rule

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Recap

Mock is an option, not a rule

Tests are first citizens

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Recap

Mock is an option, not a rule

Tests are first citizens

Don’t let mocks ruin your quality

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Recap

Mock is an option, not a rule

Tests are first citizens

Don’t let mocks ruin your quality

Remember TDD

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Recap

Mock is an option, not a rule

Tests are first citizens

Don’t let mocks ruin your quality

Remember TDD

Long Live and Prosper to Tests

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Engage

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Contents

https://github.com/lordofthejars/foobank/

viernes 18 de octubre de 13

www.lordofthejars - @alexsotobAlex Soto

Questions?

Let the end of the world come tumbling down, I'll be the last man standing on the ground - Alive - MeatLoaf

Alex Sotowww.lordofthejars.com@alexsotob

viernes 18 de octubre de 13