Date post: | 10-May-2015 |
Category: |
Technology |
Upload: | alex-soto |
View: | 4,508 times |
Download: | 0 times |
[email protected] - 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
Mock E-mail access
viernes 18 de octubre de 13
www.lordofthejars - @alexsotobAlex Soto
Mock E-mail access
Fast
Offline
viernes 18 de octubre de 13
www.lordofthejars - @alexsotobAlex Soto
Mock E-mail access
Fast
Offline
javax.mail
viernes 18 de octubre de 13
www.lordofthejars - @alexsotobAlex Soto
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
Embeddable SMTP server
viernes 18 de octubre de 13
www.lordofthejars - @alexsotobAlex Soto
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("[email protected]").addTo("[email protected]")! ! ! ! .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
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("[email protected]").addTo("[email protected]")! ! ! ! .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
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("[email protected]").addTo("[email protected]")! ! ! ! .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
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("[email protected]").addTo("[email protected]")! ! ! ! .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