SlideShare a Scribd company logo
1 of 73
Download to read offline
Testing For Unicorns
Java test apps any developer should know
Alex Soto

Red Hat Engineer

@alexsotob
@alexsotob2
Alex Soto
Red Hat Engineer
www.lordofthejars.com
@alexsotob
Who Am I?
@alexsotob3
https://www.manning.com/books/testing-java-microservices
@alexsotob4
Questions
@alexsotob5
ASSERTIONS
@alexsotob
JUnit Test
@Test
public void should_find_composer_by_name() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart");
// Then:
assertEquals("Wolfgang Amadeus Mozart", mozart.getName());
assertEquals(Era.CLASSICAL, mozart.getEra());
assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate());
assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied());
}
6
Readable name
BDD style
AssertEquals Order
Depends On Equals
@alexsotob7
AssertJ
@alexsotob
AssertJ Test
import static org.assertj.core.api.Assertions.assertThat;
@Test
public void should_find_composer_by_name() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart”);
// Then:
assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart”);
assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName);
assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27));
assertThat(mozart).isEqualToComparingFieldByField(expectedMozart);
assertThat(mozart).isEqualToIgnoringNullFields(expectedMozart);
}
8
Static Import
Readable Assertions
Not Depending on
Equals
@alexsotob
AssertJ Test Collections
@Test
public void should_find_operas_by_composer_name() {
// Given:
Composers composers = new Composers();
// When:
final List<Opera> operas = composers.findOperasByComposerName("Wolfgang Amadeus Mozart");
// Then:
assertThat(operas)
.hasSize(2)
.extracting(Opera::getName)
.containsExactlyInAnyOrder("Die Zauberflöte", "Don Giovanni”);
}
9
Train Call (IDE
support) Create List with
getName Result
Methods for String
@alexsotob
AssertJ Soft Assertions
@Test
public void should_find_composer_by_name_soft_assertions() {
// Given:
Composers composers = new Composers();
// When:
final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart");
// Then:
SoftAssertions.assertSoftly(softly -> {
softly.assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart");
softly.assertThat(mozart.getEra()).isEqualTo(Era.CLASSICAL);
softly.assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27));
softly.assertThat(mozart.getDied()).isEqualTo(LocalDate.of(1791, 12, 5));
});
}
10
Java 8 Lambda
All assertions in Block
@alexsotob11
Things go
Wrong
@alexsotob
Try/Catch
@Test
public void should_throw_exception_if_composer_not_found() {
// Given:
Composers composers = new Composers();
// When:
try {
final Composer salieri = composers.findComposerByName("Antonio Salieri");
fail();
} catch (IllegalArgumentException e) {
// Then:
assertEquals("Composer Antonio Salieri is not found", e.getMessage());
}
}
12
Fails if Success
@alexsotob
JUnit
@Test(expected = IllegalArgumentException.class)
public void should_throw_exception_if_composer_not_found_version_2() {
// Given:
Composers composers = new Composers();
// When:
final Composer salieri = composers.findComposerByName("Antonio Salieri");
}
13
Special Attribute
@alexsotob
AssertJ Exceptions
@Test
public void should_throw_exception_if_composer_not_found_version_3() {
// Given:
Composers composers = new Composers();
// When:
Throwable thrown = catchThrowable(() -> composers.findComposerByName("Antonio Salieri"));
// Then:
assertThat(thrown).isInstanceOf(IllegalArgumentException.class)
.withFailMessage("Composer Antonio Salieri is not found”);
}
14
Catch Exception of Lambda
Assertion Methods for
Exceptions
@alexsotob15
DEMO
@alexsotob16
Benefits of AssertJ
> IDE Friendly
Ctrl + Space works
> Assertions Generation
ComposerAssert.assertThat(mozart).hasName(“Mozart”).hasBirthdate(LocalDate.of(..);
> Out-of-the-Box Assertions
Guava, Joda, DB, Neo4j and Swing
@alexsotob17
Don’t Sleep, Just Wait
@alexsotob
Asynchronous Call
@Test
public void should_play_operas() throws InterruptedException {
// Given:
final Opera nozzeDiFigaro = ...;
Gramophone gramophone = new Gramophone();
// When:
gramophone.play(nozzeDiFigaro);
// Then:
TimeUnit.SECONDS.sleep(3);
assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro);
}
18
Asynchronous Call
Slowest Machine Time
@alexsotob19
@alexsotob
Awaitility Example
@Test
public void should_play_operas_version_2() {
// Given:
final Opera nozzeDiFigaro = Composers.OperaFactory
.createOpera("Le Nozze di Figaro")
.language(Language.ITALIAN).librettist("Lorenzo Da Ponte")
.roles("Count Almaviva", "Countess Rosina", "Susanna", "Figaro")
.build();
Gramophone gramophone = new Gramophone();
// When:
gramophone.play(nozzeDiFigaro);
// Then:
await().atMost(5, TimeUnit.SECONDS).until(gramophone::isPlaying);
assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro);
}
20
Asynchronous Call
Polls until True or Timeout
@alexsotob21
DEMO
@alexsotob22
Benefits of Awaitility
> Deadlock Detection
> Different Pollings
Fixed, Fibonacci, Iterative, Custom
> Simple Library
No dependencies, No magic
@alexsotob23
REST API
@alexsotob
GET /Ludwig+van+Beethoven
{
"name": "Ludwig van Beethoven",
"era": "ROMANTIC",
"birthdate": {},
"died": {},
"operas": [
{
"name": "Fidelio",
"librettist": "Georg Friedrich Treitschke",
"language": "GERMAN",
"roles": ["Rocco", "Leonore", "Florestan"]
}
]
}
24
Simple Objects
Array of Objects
@alexsotob
HttpClient Example
@Test
public void should_find_composer() throws IOException, URISyntaxException {
// Given:
URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/");
uriBuilder.setPath("Ludwig van Beethoven");
// When:
final Content bodyContent = Request.Get(uriBuilder.build())
.execute().returnContent();
String body = bodyContent.asString();
// Then:
assertThat(body).contains(""name":"Ludwig van Beethoven"")
.contains(""librettist":"Georg Friedrich Treitschke"");
}
25
Prepare Connection
Do connection
Get content
Manipulate String
@alexsotob
WebDriver Example
// Given:
WebDriver browser = new FirefoxDriver();
URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/");
uriBuilder.setPath("Ludwig van Beethoven");
// When:
browser.navigate().to(uriBuilder.build());
// Then:
assertThat(browser.getPageSource()).contains(""name":"Ludwig van Beethoven"");
26
@alexsotob27
@alexsotob
REST-assured Example
@Test
public void should_find_composer() {
given()
.when()
.get("{composer}", "Ludwig van Beethoven")
.then()
.assertThat()
.body("name", is("Ludwig van Beethoven"))
.body("operas.size()", is(1))
.body("operas.name", hasItems("Fidelio"));
}
28
GET Http Method with
Placeholders
GPath Expression
@alexsotob
REST-assured Example
@Test
public void should_insert_composer() {
Composer composer = ....;
given()
.param("parameter1", "parameterValue")
.body(composer)
.when()
.post()
.then()
.assertThat()
.statusCode(201);
}
29
Create POJO object
Set Params
Set POJO as Body
POST Http Method
Assertion on Status Code
@alexsotob
REST-assured Request Logging
given().log().all(). .. // Log all request specification details
given().log().params(). .. // Log only the parameters of the request
given().log().body(). .. // Log only the request body
given().log().headers(). .. // Log only the request headers
given().log().cookies(). .. // Log only the request cookies
given().log().method(). .. // Log only the request method
given().log().path(). .. // Log only the request path
30
@alexsotob
REST-assured Response Logging
get("/x").then().log().ifError()
get("/x").then().log().all()
given().log().ifValidationFails()
get("/x").then().log().ifStatusCodeIsEqualTo(302)
given().config(RestAssured.config()
.logConfig(logConfig().enableLoggingOfRequestAndResponseIfValidationFails())
)
31
@alexsotob
REST-assured Request Specification
.get("http://example.com/{composer}", "Ludwig van Beethoven")
RequestSpecBuilder builder = new RequestSpecBuilder();
builder.setBaseUri("http://example.com");
given().spec(builder.build())...
32
Use domain directly
Use Spec Builder
Reuse Everywhere
@alexsotob
REST-assured Auth
given().auth().oauth2(accessToken).when()...
given().auth().form("John", "Doe", springSecurity().withCsrfFieldName("_csrf")).when()...
given().auth().basic("username", "password").when()...
33
@alexsotob34
More Features of Rest-Assured
> Custom Parsers
Not just JSON and XML
> SSL Support
.relaxedHTTPSValidation()
> Filters
Input/Output modification
> JSON Schema Validation
Content not Important
@alexsotob35
Service Virtualization
@alexsotob
Service Virtualization Capture Mode
36
Service A External Network Service B
Scripts
Proxy
@alexsotob
Service Virtualization Simulate Mode
37
Service A External Network Service B
Scripts
Proxy
@alexsotob38
@alexsotob
Hoverfly Example
@ClassRule
public static HoverflyRule hoverflyRule =
HoverflyRule.inCaptureOrSimulationMode("getcomposers.json");
@Test
public void should_get_composers_from_composers_microservice() {
// Given:
ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081);
// When:
Composer composer = composersGateway.getComposer("Ludwig van Beethoven");
// Then:
assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven");
}
39
Start Hoverfly
Use Real Host
Get Data from Real
{
"data" : {
"pairs" : [{
"request" : {
"path" : "/Ludwig van Beethoven",
"method" : "GET",
"destination" : “operas.com:8081",
...
}
"response" : {
"status" : 200,
"body" : "{"name":"Ludwig van Beethoven",}",
"encodedBody" : false,
"headers" : {
"Connection" : [ "keep-alive" ],
...
}
}
}
}
Get Data from Proxy
@alexsotob
Hoverfly Example Simulate
private static String RESPONSE = "[n"
+ " {n"
+ " "name": "Moon",n"
+ " "villain": "Gru",n"
+ " "wiki": "https://en.wikipedia.org/wiki/Moon"n"
+ " }
+ "]";
@ClassRule
public static HoverflyRule hoverflyRule =
HoverflyRule.inSimulationMode(dsl(
service("crimesdb:8080")
.get("/crimes/Gru")
.willReturn(success(RESPONSE, "application/json"))
40
Hardcoded response
Starts in simulate
Host
Program interactions
@alexsotob41
Benefits of Service Virtualization and Hoverfly
> Do not relay on network
Yet testing all stack trace
> Hoverfly multilanguage
Can be used as standalone proxy
> Hoverfly JVM
Integration with JVM proxy settings
@alexsotob42
Contract Tests
@alexsotob43
Consumer
request
response Stub Server
expectations
Provider
request
response
Result
Define Consumer Expectations Verify Expectations On Provider
@alexsotob44
@RunWith(Arquillian.class)
public class CrimesConsumerContractTest {
@StubServer URL pactServer;
@Pact(provider = "crimes", consumer = "villains")
public RequestResponsePact returnListOfCrimes(PactDslWithProvider builder) {
return builder
.uponReceiving("Gru villain to get all Crimes")
.path("/crimes/Gru")
.method("GET")
.willRespondWith()
.status(200)
.body(RESPONSE)
.toPact();
}
@Test
@PactVerification("crimes")
public void should_get_list_of_crimes_by_villain() {
CrimesGateway crimesGateway = new CrimesGateway(webClient, pactServer);
final Single<JsonArray> gruCrimes = crimesGateway.getCrimesByVillainName("Gru");
}
Stub/proxy Server URL
Defines service interaction
Provides predefined Req/Res
Executes real requests
Consumer side
@alexsotob45
@RunWith(Arquillian.class)
@Provider("crimes")
@ContractsFolder("~/crimescontract")
public class CrimesContractTest {
@ArquillianResource
Target target;
@Test
public void should_validate_contract() {
assertThat(target).withUrl(getCrimesServer()).satisfiesContract();
}
}
Provider under validation
Location of contracts
Http Client
Asserts All Interactions are correct
Provider side
@alexsotob46
DEMO
@alexsotob47
Benefits of CDC and Pact
> Pact Foundation
Pact specification v3
> Integration with several languages
JVM, Ruby, Python, Go, .Net, Swift, JS
> Pact Broker
Sharing contracts, API documentation, Overview of services
> Arquillian Algeron
Arquillian ecosystem + Pact, Publishers/Retrievers, JBoss Forge
> Consumer Driven Contracts
Fail fast
Independent deployments
Improve communication
@alexsotob48
Containers Are Burning
@alexsotob
Testing Containers
docker build -t myorg/myservice:1.0.0 .
docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0
docker-compose up
mvn clean test
docker-compose stop
49
Docker Run
Docker Compose Run
Run tests
Stop Docker Containers
@alexsotob50
@alexsotob
Arquillian Cube Example
@RunWith(Arquillian.class)
public class HelloWorldTest {
@ArquillianResource
@DockerUrl(containerName = "helloworld", exposedPort = 8080)
RequestSpecBuilder requestSpecBuilder;
@Test
public void should_receive_ok_message() {
RestAssured
.given()
.spec(requestSpecBuilder.build())
.when()
.get()
.then()
.assertThat().body("status", equalTo("OK"));
}
}
51
Arquillian Runner
REST-Assured Integration
Environment Resolver
Normal REST-Assured Call
helloworld:
image: jonmorehouse/ping-pong
ports:
- "8080:8080"
src/test/docker/docker-compose.yml
@alexsotob
Arquillian Cube DSL
@RunWith(SpringRunner.class)
@SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT)
@ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class)
public class PingPongSpringBootTest {
@ClassRule
public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6")
.withPortBinding(6379);
@Autowired
TestRestTemplate restTemplate;
@Test
public void should_get_data_from_redis() {
}
52
Spring Boot Test
Custom Initializer
Container Definition
public static class Initializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
EnvironmentTestUtils.addEnvironment("testcontainers",
configurableApplicationContext.getEnvironment(),
"spring.redis.host=" + redis.getIpAddress(),
"spring.redis.port=" + redis.getBindPort(6379)
);
Sets Container Environment
@alexsotob53
DEMO
@alexsotob
Arquillian Kube
@RunWith(Arquillian.class)
public class HelloWorldTest {
@ArquillianResource
KubernetesClient client;
@Named(“hello-world-service")
@PortForward
@ArquillianResource
URL url;
@Test
public void testRunningPodStaysUp() throws Exception {
assertThat(client).deployments().pods().isPodReadyForPeriod();
}
}
54
Kubernetes Client
URL to Access Service
AssertJ Custom Assertions
@alexsotob55
Persistence Tests
@alexsotob
First attempt
@Test
public void should_find_composer_by_name() {
// Given:
clearDatabase(jdbcUri);
insertComposersData(jdbcUri);
ComposersRepository composersRepository = new ComposersRepository();
// When:
Composer mozart = composersRepository.findComposerByName("Wolfgang Amadeus Mozart");
// Then:
assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName);
}
56
Prepare Database
Execute Query
@alexsotob57
APE
@alexsotob
APE SQL example
@Rule
public ArquillianPersistenceRule arquillianPersistenceRule =
new ArquillianPersistenceRule();
@DbUnit
@ArquillianResource
RdbmsPopulator rdbmsPopulator;
@Before
public void populateData() {
// Given:
rdbmsPopulator.forUri(jdbcUri).withDriver(Driver.class).withUsername("sa")
.withPassword("").usingDataSet("composers.yml")
.execute();
}
58
APE JUnit Rule
(not necessary with
Arquillian Runner)
Set DBUnit usage
Configure Connection and Dataset
Populate
composers:
- id: 1
name: Wolfgang Amadeus Mozart
birthdate: 27/1/1756
died: 5/12/1791
@alexsotob
APE SQL example
@After
public void clean_database() {
// Given:
rdbmsPopulator.forUri(jdbcUri).withDriver(Driver.class).withUsername("sa")
.withPassword("").usingDataSet("composers.yml")
.clean();
}
59
Clean After Test
Clean Database
@alexsotob60
DEMO
@alexsotob61
Benefits of Arquillian APE
> Boilerplate Code
> Programmatic/Declarative
@UsingDataSet/@ShouldMatchDataSet
> SQL Support
DBUnit and Flyway
> RESTAPI Support
Postman Collections
> NoSQL Support
MongoDB, Couchbase, CouchDB, Vault, Redis, Infinispan
@alexsotob62
Speeding Test Execution
@alexsotob63
Production Sources Tests
https://martinfowler.com/articles/rise-test-impact-analysis.html
@alexsotob
Smart Testing Maven Extension
curl -sSL https://git.io/v5jy6 | bash
64
Installs extension
mvn clean test -Dsmart.testing="new, changed, affected"
Runs only new, changed and prod related tests
mvn clean test -Dsmart.testing.mode=ordering -Dsmart.testing="new, changed, affected”
Prioritize new, changed and prod related tests
@alexsotob65
DEMO
@alexsotob66
More about Smart Testing
> Heuristics
new, changed, affected, failed and categorized
> Range of Commits
Define where you want to look at
> Configuration
System Properties or YAML file (global or per module)
> Jenkins Pipeline Shared Library
Integrate with your CI/CD pipeline
> Detection of none class changes
@WatchFile("src/main/resources/META-INF/
> Surefire based
Works with any kind of test that can be run in Surefire
@alexsotob67
Regression-free versions
@alexsotob68
Diferencia
@alexsotob69
Simple Comparison
@alexsotob70
Noise Detection Comparison
@alexsotob71
DEMO
@alexsotob72
More about Diferencia
> Comparison
with, without noise detection, strict, subset
> Formats supported
JSON, Plain Text (automatic detection), HTTPS
> Monitoring
HTTP Status, Prometheus
> Rest API
Configure, Stats
> Docker Image
Ready to use in Kubernetes and OpenShift
https://developers.redhat.com/
@alexsotob
asotobue@redhat.com

More Related Content

What's hot

LISA QooxdooTutorial Slides
LISA QooxdooTutorial SlidesLISA QooxdooTutorial Slides
LISA QooxdooTutorial SlidesTobias Oetiker
 
201913046 wahyu septiansyah network programing
201913046 wahyu septiansyah network programing201913046 wahyu septiansyah network programing
201913046 wahyu septiansyah network programingwahyuseptiansyah
 
20110424 action scriptを使わないflash勉強会
20110424 action scriptを使わないflash勉強会20110424 action scriptを使わないflash勉強会
20110424 action scriptを使わないflash勉強会Hiroki Mizuno
 
Celluloid - Beyond Sidekiq
Celluloid - Beyond SidekiqCelluloid - Beyond Sidekiq
Celluloid - Beyond SidekiqMarcelo Pinheiro
 
TDOH x 台科 pwn課程
TDOH x 台科 pwn課程TDOH x 台科 pwn課程
TDOH x 台科 pwn課程Weber Tsai
 
Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011Anton Arhipov
 
Unit testing en iOS @ MobileCon Galicia
Unit testing en iOS @ MobileCon GaliciaUnit testing en iOS @ MobileCon Galicia
Unit testing en iOS @ MobileCon GaliciaRobot Media
 
Unit Testing: Special Cases
Unit Testing: Special CasesUnit Testing: Special Cases
Unit Testing: Special CasesCiklum Ukraine
 
Binaries Are Not Only Output
Binaries Are Not Only OutputBinaries Are Not Only Output
Binaries Are Not Only OutputHajime Morrita
 
A exception ekon16
A exception ekon16A exception ekon16
A exception ekon16Max Kleiner
 
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloadingJEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloadingAnton Arhipov
 
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516SOAT
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockRobot Media
 
Endevor api an introduction to the endevor application programming interface
Endevor api   an introduction to the endevor application programming interface Endevor api   an introduction to the endevor application programming interface
Endevor api an introduction to the endevor application programming interface Kevin Grimes
 

What's hot (20)

LISA QooxdooTutorial Slides
LISA QooxdooTutorial SlidesLISA QooxdooTutorial Slides
LISA QooxdooTutorial Slides
 
201913046 wahyu septiansyah network programing
201913046 wahyu septiansyah network programing201913046 wahyu septiansyah network programing
201913046 wahyu septiansyah network programing
 
Live Updating Swift Code
Live Updating Swift CodeLive Updating Swift Code
Live Updating Swift Code
 
20110424 action scriptを使わないflash勉強会
20110424 action scriptを使わないflash勉強会20110424 action scriptを使わないflash勉強会
20110424 action scriptを使わないflash勉強会
 
Botsing demo
Botsing demoBotsing demo
Botsing demo
 
Celluloid - Beyond Sidekiq
Celluloid - Beyond SidekiqCelluloid - Beyond Sidekiq
Celluloid - Beyond Sidekiq
 
TDOH x 台科 pwn課程
TDOH x 台科 pwn課程TDOH x 台科 pwn課程
TDOH x 台科 pwn課程
 
Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011Java Bytecode for Discriminating Developers - JavaZone 2011
Java Bytecode for Discriminating Developers - JavaZone 2011
 
Unit testing en iOS @ MobileCon Galicia
Unit testing en iOS @ MobileCon GaliciaUnit testing en iOS @ MobileCon Galicia
Unit testing en iOS @ MobileCon Galicia
 
Ecma script 5
Ecma script 5Ecma script 5
Ecma script 5
 
Unit Testing: Special Cases
Unit Testing: Special CasesUnit Testing: Special Cases
Unit Testing: Special Cases
 
Binaries Are Not Only Output
Binaries Are Not Only OutputBinaries Are Not Only Output
Binaries Are Not Only Output
 
Stop Monkeys Fall
Stop Monkeys FallStop Monkeys Fall
Stop Monkeys Fall
 
A exception ekon16
A exception ekon16A exception ekon16
A exception ekon16
 
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloadingJEEConf 2017 - The hitchhiker’s guide to Java class reloading
JEEConf 2017 - The hitchhiker’s guide to Java class reloading
 
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
 
Easy Button
Easy ButtonEasy Button
Easy Button
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
 
TDD per Webapps
TDD per WebappsTDD per Webapps
TDD per Webapps
 
Endevor api an introduction to the endevor application programming interface
Endevor api   an introduction to the endevor application programming interface Endevor api   an introduction to the endevor application programming interface
Endevor api an introduction to the endevor application programming interface
 

Similar to Testing for Unicorns

Testing Java Microservices Devoxx be 2017
Testing Java Microservices Devoxx be 2017Testing Java Microservices Devoxx be 2017
Testing Java Microservices Devoxx be 2017Alex Soto
 
Ast transformations
Ast transformationsAst transformations
Ast transformationsHamletDRC
 
AST Transformations
AST TransformationsAST Transformations
AST TransformationsHamletDRC
 
Expression trees in c#
Expression trees in c#Expression trees in c#
Expression trees in c#Oleksii Holub
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6Solution4Future
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokusHamletDRC
 
Introduction aux Macros
Introduction aux MacrosIntroduction aux Macros
Introduction aux Macrosunivalence
 
Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Alina Vilk
 
A topology of memory leaks on the JVM
A topology of memory leaks on the JVMA topology of memory leaks on the JVM
A topology of memory leaks on the JVMRafael Winterhalter
 
MiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScriptMiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScriptCaridy Patino
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)HamletDRC
 
Deep Dive into Zone.JS
Deep Dive into Zone.JSDeep Dive into Zone.JS
Deep Dive into Zone.JSIlia Idakiev
 
Androidの本当にあった怖い話
Androidの本当にあった怖い話Androidの本当にあった怖い話
Androidの本当にあった怖い話Yusuke Yamamoto
 
Introduction to jRuby
Introduction to jRubyIntroduction to jRuby
Introduction to jRubyAdam Kalsey
 

Similar to Testing for Unicorns (20)

Testing Java Microservices Devoxx be 2017
Testing Java Microservices Devoxx be 2017Testing Java Microservices Devoxx be 2017
Testing Java Microservices Devoxx be 2017
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
 
AST Transformations
AST TransformationsAST Transformations
AST Transformations
 
Unfiltered Unveiled
Unfiltered UnveiledUnfiltered Unveiled
Unfiltered Unveiled
 
wtf is in Java/JDK/wtf7?
wtf is in Java/JDK/wtf7?wtf is in Java/JDK/wtf7?
wtf is in Java/JDK/wtf7?
 
Expression trees in c#
Expression trees in c#Expression trees in c#
Expression trees in c#
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 
Jasmine BDD for Javascript
Jasmine BDD for JavascriptJasmine BDD for Javascript
Jasmine BDD for Javascript
 
Introduction aux Macros
Introduction aux MacrosIntroduction aux Macros
Introduction aux Macros
 
Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)Expression trees in c#, Алексей Голубь (Svitla Systems)
Expression trees in c#, Алексей Голубь (Svitla Systems)
 
A topology of memory leaks on the JVM
A topology of memory leaks on the JVMA topology of memory leaks on the JVM
A topology of memory leaks on the JVM
 
Nantes Jug - Java 7
Nantes Jug - Java 7Nantes Jug - Java 7
Nantes Jug - Java 7
 
MiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScriptMiamiJS - The Future of JavaScript
MiamiJS - The Future of JavaScript
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)
 
Deep Dive into Zone.JS
Deep Dive into Zone.JSDeep Dive into Zone.JS
Deep Dive into Zone.JS
 
Androidの本当にあった怖い話
Androidの本当にあった怖い話Androidの本当にあった怖い話
Androidの本当にあった怖い話
 
Introduction to jRuby
Introduction to jRubyIntroduction to jRuby
Introduction to jRuby
 
Groovy
GroovyGroovy
Groovy
 

More from Alex Soto

Kubernetes Native Java
Kubernetes Native JavaKubernetes Native Java
Kubernetes Native JavaAlex Soto
 
Reactive Programming for Real Use Cases
Reactive Programming for Real Use CasesReactive Programming for Real Use Cases
Reactive Programming for Real Use CasesAlex Soto
 
Chaos Engineering Kubernetes
Chaos Engineering KubernetesChaos Engineering Kubernetes
Chaos Engineering KubernetesAlex Soto
 
Chaos Engineering Kubernetes
Chaos Engineering KubernetesChaos Engineering Kubernetes
Chaos Engineering KubernetesAlex Soto
 
Microservices testing and automation
Microservices testing and automationMicroservices testing and automation
Microservices testing and automationAlex Soto
 
Testing in Production: From DevTestOops to DevTestOps
Testing in Production: From DevTestOops to DevTestOpsTesting in Production: From DevTestOops to DevTestOps
Testing in Production: From DevTestOops to DevTestOpsAlex Soto
 
Supersonic Subatomic Java
Supersonic Subatomic JavaSupersonic Subatomic Java
Supersonic Subatomic JavaAlex Soto
 
From DevTestOops to DevTestOps
From DevTestOops to DevTestOpsFrom DevTestOops to DevTestOps
From DevTestOops to DevTestOpsAlex Soto
 
Istio service mesh & pragmatic microservices architecture
Istio service mesh & pragmatic microservices architectureIstio service mesh & pragmatic microservices architecture
Istio service mesh & pragmatic microservices architectureAlex Soto
 
Zero Downtime Deployment in Microservices era
Zero Downtime Deployment in Microservices eraZero Downtime Deployment in Microservices era
Zero Downtime Deployment in Microservices eraAlex Soto
 
Service Mesh Patterns
Service Mesh PatternsService Mesh Patterns
Service Mesh PatternsAlex Soto
 
Supersonic, Subatomic Java
Supersonic, Subatomic JavaSupersonic, Subatomic Java
Supersonic, Subatomic JavaAlex Soto
 
Zero Downtime Deployment in Microservices era
Zero Downtime Deployment in Microservices eraZero Downtime Deployment in Microservices era
Zero Downtime Deployment in Microservices eraAlex Soto
 
Long Live and Prosper To Monolith
Long Live and Prosper To MonolithLong Live and Prosper To Monolith
Long Live and Prosper To MonolithAlex Soto
 
Sail in the cloud - An intro to Istio commit
Sail in the cloud - An intro to Istio commitSail in the cloud - An intro to Istio commit
Sail in the cloud - An intro to Istio commitAlex Soto
 
KubeBoot - Spring Boot deployment on Kubernetes
KubeBoot - Spring Boot deployment on KubernetesKubeBoot - Spring Boot deployment on Kubernetes
KubeBoot - Spring Boot deployment on KubernetesAlex Soto
 
Sail in the Cloud - An intro to Istio
Sail in the Cloud  - An intro to IstioSail in the Cloud  - An intro to Istio
Sail in the Cloud - An intro to IstioAlex Soto
 
Testing XXIst Century
Testing XXIst CenturyTesting XXIst Century
Testing XXIst CenturyAlex Soto
 
Arquillian Constellation
Arquillian ConstellationArquillian Constellation
Arquillian ConstellationAlex Soto
 
Live Long and Prosper to Monolith
Live Long and Prosper to MonolithLive Long and Prosper to Monolith
Live Long and Prosper to MonolithAlex Soto
 

More from Alex Soto (20)

Kubernetes Native Java
Kubernetes Native JavaKubernetes Native Java
Kubernetes Native Java
 
Reactive Programming for Real Use Cases
Reactive Programming for Real Use CasesReactive Programming for Real Use Cases
Reactive Programming for Real Use Cases
 
Chaos Engineering Kubernetes
Chaos Engineering KubernetesChaos Engineering Kubernetes
Chaos Engineering Kubernetes
 
Chaos Engineering Kubernetes
Chaos Engineering KubernetesChaos Engineering Kubernetes
Chaos Engineering Kubernetes
 
Microservices testing and automation
Microservices testing and automationMicroservices testing and automation
Microservices testing and automation
 
Testing in Production: From DevTestOops to DevTestOps
Testing in Production: From DevTestOops to DevTestOpsTesting in Production: From DevTestOops to DevTestOps
Testing in Production: From DevTestOops to DevTestOps
 
Supersonic Subatomic Java
Supersonic Subatomic JavaSupersonic Subatomic Java
Supersonic Subatomic Java
 
From DevTestOops to DevTestOps
From DevTestOops to DevTestOpsFrom DevTestOops to DevTestOps
From DevTestOops to DevTestOps
 
Istio service mesh & pragmatic microservices architecture
Istio service mesh & pragmatic microservices architectureIstio service mesh & pragmatic microservices architecture
Istio service mesh & pragmatic microservices architecture
 
Zero Downtime Deployment in Microservices era
Zero Downtime Deployment in Microservices eraZero Downtime Deployment in Microservices era
Zero Downtime Deployment in Microservices era
 
Service Mesh Patterns
Service Mesh PatternsService Mesh Patterns
Service Mesh Patterns
 
Supersonic, Subatomic Java
Supersonic, Subatomic JavaSupersonic, Subatomic Java
Supersonic, Subatomic Java
 
Zero Downtime Deployment in Microservices era
Zero Downtime Deployment in Microservices eraZero Downtime Deployment in Microservices era
Zero Downtime Deployment in Microservices era
 
Long Live and Prosper To Monolith
Long Live and Prosper To MonolithLong Live and Prosper To Monolith
Long Live and Prosper To Monolith
 
Sail in the cloud - An intro to Istio commit
Sail in the cloud - An intro to Istio commitSail in the cloud - An intro to Istio commit
Sail in the cloud - An intro to Istio commit
 
KubeBoot - Spring Boot deployment on Kubernetes
KubeBoot - Spring Boot deployment on KubernetesKubeBoot - Spring Boot deployment on Kubernetes
KubeBoot - Spring Boot deployment on Kubernetes
 
Sail in the Cloud - An intro to Istio
Sail in the Cloud  - An intro to IstioSail in the Cloud  - An intro to Istio
Sail in the Cloud - An intro to Istio
 
Testing XXIst Century
Testing XXIst CenturyTesting XXIst Century
Testing XXIst Century
 
Arquillian Constellation
Arquillian ConstellationArquillian Constellation
Arquillian Constellation
 
Live Long and Prosper to Monolith
Live Long and Prosper to MonolithLive Long and Prosper to Monolith
Live Long and Prosper to Monolith
 

Recently uploaded

%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in sowetomasabamasaba
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Bert Jan Schrijver
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...masabamasaba
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...Shane Coughlan
 
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
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is insideshinachiaurasa2
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...masabamasaba
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareJim McKeeth
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastPapp Krisztián
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024VictoriaMetrics
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfkalichargn70th171
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2
 
+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
 

Recently uploaded (20)

%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
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
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
+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...
 

Testing for Unicorns

  • 1. Testing For Unicorns Java test apps any developer should know Alex Soto
 Red Hat Engineer
 @alexsotob
  • 2. @alexsotob2 Alex Soto Red Hat Engineer www.lordofthejars.com @alexsotob Who Am I?
  • 6. @alexsotob JUnit Test @Test public void should_find_composer_by_name() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart"); // Then: assertEquals("Wolfgang Amadeus Mozart", mozart.getName()); assertEquals(Era.CLASSICAL, mozart.getEra()); assertEquals(LocalDate.of(1756, 1, 27), mozart.getBirthdate()); assertEquals(LocalDate.of(1791, 12, 5), mozart.getDied()); } 6 Readable name BDD style AssertEquals Order Depends On Equals
  • 8. @alexsotob AssertJ Test import static org.assertj.core.api.Assertions.assertThat; @Test public void should_find_composer_by_name() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart”); // Then: assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart”); assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName); assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27)); assertThat(mozart).isEqualToComparingFieldByField(expectedMozart); assertThat(mozart).isEqualToIgnoringNullFields(expectedMozart); } 8 Static Import Readable Assertions Not Depending on Equals
  • 9. @alexsotob AssertJ Test Collections @Test public void should_find_operas_by_composer_name() { // Given: Composers composers = new Composers(); // When: final List<Opera> operas = composers.findOperasByComposerName("Wolfgang Amadeus Mozart"); // Then: assertThat(operas) .hasSize(2) .extracting(Opera::getName) .containsExactlyInAnyOrder("Die Zauberflöte", "Don Giovanni”); } 9 Train Call (IDE support) Create List with getName Result Methods for String
  • 10. @alexsotob AssertJ Soft Assertions @Test public void should_find_composer_by_name_soft_assertions() { // Given: Composers composers = new Composers(); // When: final Composer mozart = composers.findComposerByName("Wolfgang Amadeus Mozart"); // Then: SoftAssertions.assertSoftly(softly -> { softly.assertThat(mozart.getName()).isEqualTo("Wolfgang Amadeus Mozart"); softly.assertThat(mozart.getEra()).isEqualTo(Era.CLASSICAL); softly.assertThat(mozart.getBirthdate()).isEqualTo(LocalDate.of(1756, 1, 27)); softly.assertThat(mozart.getDied()).isEqualTo(LocalDate.of(1791, 12, 5)); }); } 10 Java 8 Lambda All assertions in Block
  • 12. @alexsotob Try/Catch @Test public void should_throw_exception_if_composer_not_found() { // Given: Composers composers = new Composers(); // When: try { final Composer salieri = composers.findComposerByName("Antonio Salieri"); fail(); } catch (IllegalArgumentException e) { // Then: assertEquals("Composer Antonio Salieri is not found", e.getMessage()); } } 12 Fails if Success
  • 13. @alexsotob JUnit @Test(expected = IllegalArgumentException.class) public void should_throw_exception_if_composer_not_found_version_2() { // Given: Composers composers = new Composers(); // When: final Composer salieri = composers.findComposerByName("Antonio Salieri"); } 13 Special Attribute
  • 14. @alexsotob AssertJ Exceptions @Test public void should_throw_exception_if_composer_not_found_version_3() { // Given: Composers composers = new Composers(); // When: Throwable thrown = catchThrowable(() -> composers.findComposerByName("Antonio Salieri")); // Then: assertThat(thrown).isInstanceOf(IllegalArgumentException.class) .withFailMessage("Composer Antonio Salieri is not found”); } 14 Catch Exception of Lambda Assertion Methods for Exceptions
  • 16. @alexsotob16 Benefits of AssertJ > IDE Friendly Ctrl + Space works > Assertions Generation ComposerAssert.assertThat(mozart).hasName(“Mozart”).hasBirthdate(LocalDate.of(..); > Out-of-the-Box Assertions Guava, Joda, DB, Neo4j and Swing
  • 18. @alexsotob Asynchronous Call @Test public void should_play_operas() throws InterruptedException { // Given: final Opera nozzeDiFigaro = ...; Gramophone gramophone = new Gramophone(); // When: gramophone.play(nozzeDiFigaro); // Then: TimeUnit.SECONDS.sleep(3); assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro); } 18 Asynchronous Call Slowest Machine Time
  • 20. @alexsotob Awaitility Example @Test public void should_play_operas_version_2() { // Given: final Opera nozzeDiFigaro = Composers.OperaFactory .createOpera("Le Nozze di Figaro") .language(Language.ITALIAN).librettist("Lorenzo Da Ponte") .roles("Count Almaviva", "Countess Rosina", "Susanna", "Figaro") .build(); Gramophone gramophone = new Gramophone(); // When: gramophone.play(nozzeDiFigaro); // Then: await().atMost(5, TimeUnit.SECONDS).until(gramophone::isPlaying); assertThat(gramophone.getCurrentOpera()).isEqualTo(nozzeDiFigaro); } 20 Asynchronous Call Polls until True or Timeout
  • 22. @alexsotob22 Benefits of Awaitility > Deadlock Detection > Different Pollings Fixed, Fibonacci, Iterative, Custom > Simple Library No dependencies, No magic
  • 24. @alexsotob GET /Ludwig+van+Beethoven { "name": "Ludwig van Beethoven", "era": "ROMANTIC", "birthdate": {}, "died": {}, "operas": [ { "name": "Fidelio", "librettist": "Georg Friedrich Treitschke", "language": "GERMAN", "roles": ["Rocco", "Leonore", "Florestan"] } ] } 24 Simple Objects Array of Objects
  • 25. @alexsotob HttpClient Example @Test public void should_find_composer() throws IOException, URISyntaxException { // Given: URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/"); uriBuilder.setPath("Ludwig van Beethoven"); // When: final Content bodyContent = Request.Get(uriBuilder.build()) .execute().returnContent(); String body = bodyContent.asString(); // Then: assertThat(body).contains(""name":"Ludwig van Beethoven"") .contains(""librettist":"Georg Friedrich Treitschke""); } 25 Prepare Connection Do connection Get content Manipulate String
  • 26. @alexsotob WebDriver Example // Given: WebDriver browser = new FirefoxDriver(); URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/"); uriBuilder.setPath("Ludwig van Beethoven"); // When: browser.navigate().to(uriBuilder.build()); // Then: assertThat(browser.getPageSource()).contains(""name":"Ludwig van Beethoven""); 26
  • 28. @alexsotob REST-assured Example @Test public void should_find_composer() { given() .when() .get("{composer}", "Ludwig van Beethoven") .then() .assertThat() .body("name", is("Ludwig van Beethoven")) .body("operas.size()", is(1)) .body("operas.name", hasItems("Fidelio")); } 28 GET Http Method with Placeholders GPath Expression
  • 29. @alexsotob REST-assured Example @Test public void should_insert_composer() { Composer composer = ....; given() .param("parameter1", "parameterValue") .body(composer) .when() .post() .then() .assertThat() .statusCode(201); } 29 Create POJO object Set Params Set POJO as Body POST Http Method Assertion on Status Code
  • 30. @alexsotob REST-assured Request Logging given().log().all(). .. // Log all request specification details given().log().params(). .. // Log only the parameters of the request given().log().body(). .. // Log only the request body given().log().headers(). .. // Log only the request headers given().log().cookies(). .. // Log only the request cookies given().log().method(). .. // Log only the request method given().log().path(). .. // Log only the request path 30
  • 32. @alexsotob REST-assured Request Specification .get("http://example.com/{composer}", "Ludwig van Beethoven") RequestSpecBuilder builder = new RequestSpecBuilder(); builder.setBaseUri("http://example.com"); given().spec(builder.build())... 32 Use domain directly Use Spec Builder Reuse Everywhere
  • 33. @alexsotob REST-assured Auth given().auth().oauth2(accessToken).when()... given().auth().form("John", "Doe", springSecurity().withCsrfFieldName("_csrf")).when()... given().auth().basic("username", "password").when()... 33
  • 34. @alexsotob34 More Features of Rest-Assured > Custom Parsers Not just JSON and XML > SSL Support .relaxedHTTPSValidation() > Filters Input/Output modification > JSON Schema Validation Content not Important
  • 36. @alexsotob Service Virtualization Capture Mode 36 Service A External Network Service B Scripts Proxy
  • 37. @alexsotob Service Virtualization Simulate Mode 37 Service A External Network Service B Scripts Proxy
  • 39. @alexsotob Hoverfly Example @ClassRule public static HoverflyRule hoverflyRule = HoverflyRule.inCaptureOrSimulationMode("getcomposers.json"); @Test public void should_get_composers_from_composers_microservice() { // Given: ComposersGateway composersGateway = new ComposersGateway("operas.com", 8081); // When: Composer composer = composersGateway.getComposer("Ludwig van Beethoven"); // Then: assertThat(composer.getName()).isEqualTo("Ludwig van Beethoven"); } 39 Start Hoverfly Use Real Host Get Data from Real { "data" : { "pairs" : [{ "request" : { "path" : "/Ludwig van Beethoven", "method" : "GET", "destination" : “operas.com:8081", ... } "response" : { "status" : 200, "body" : "{"name":"Ludwig van Beethoven",}", "encodedBody" : false, "headers" : { "Connection" : [ "keep-alive" ], ... } } } } Get Data from Proxy
  • 40. @alexsotob Hoverfly Example Simulate private static String RESPONSE = "[n" + " {n" + " "name": "Moon",n" + " "villain": "Gru",n" + " "wiki": "https://en.wikipedia.org/wiki/Moon"n" + " } + "]"; @ClassRule public static HoverflyRule hoverflyRule = HoverflyRule.inSimulationMode(dsl( service("crimesdb:8080") .get("/crimes/Gru") .willReturn(success(RESPONSE, "application/json")) 40 Hardcoded response Starts in simulate Host Program interactions
  • 41. @alexsotob41 Benefits of Service Virtualization and Hoverfly > Do not relay on network Yet testing all stack trace > Hoverfly multilanguage Can be used as standalone proxy > Hoverfly JVM Integration with JVM proxy settings
  • 44. @alexsotob44 @RunWith(Arquillian.class) public class CrimesConsumerContractTest { @StubServer URL pactServer; @Pact(provider = "crimes", consumer = "villains") public RequestResponsePact returnListOfCrimes(PactDslWithProvider builder) { return builder .uponReceiving("Gru villain to get all Crimes") .path("/crimes/Gru") .method("GET") .willRespondWith() .status(200) .body(RESPONSE) .toPact(); } @Test @PactVerification("crimes") public void should_get_list_of_crimes_by_villain() { CrimesGateway crimesGateway = new CrimesGateway(webClient, pactServer); final Single<JsonArray> gruCrimes = crimesGateway.getCrimesByVillainName("Gru"); } Stub/proxy Server URL Defines service interaction Provides predefined Req/Res Executes real requests Consumer side
  • 45. @alexsotob45 @RunWith(Arquillian.class) @Provider("crimes") @ContractsFolder("~/crimescontract") public class CrimesContractTest { @ArquillianResource Target target; @Test public void should_validate_contract() { assertThat(target).withUrl(getCrimesServer()).satisfiesContract(); } } Provider under validation Location of contracts Http Client Asserts All Interactions are correct Provider side
  • 47. @alexsotob47 Benefits of CDC and Pact > Pact Foundation Pact specification v3 > Integration with several languages JVM, Ruby, Python, Go, .Net, Swift, JS > Pact Broker Sharing contracts, API documentation, Overview of services > Arquillian Algeron Arquillian ecosystem + Pact, Publishers/Retrievers, JBoss Forge > Consumer Driven Contracts Fail fast Independent deployments Improve communication
  • 49. @alexsotob Testing Containers docker build -t myorg/myservice:1.0.0 . docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0 docker-compose up mvn clean test docker-compose stop 49 Docker Run Docker Compose Run Run tests Stop Docker Containers
  • 51. @alexsotob Arquillian Cube Example @RunWith(Arquillian.class) public class HelloWorldTest { @ArquillianResource @DockerUrl(containerName = "helloworld", exposedPort = 8080) RequestSpecBuilder requestSpecBuilder; @Test public void should_receive_ok_message() { RestAssured .given() .spec(requestSpecBuilder.build()) .when() .get() .then() .assertThat().body("status", equalTo("OK")); } } 51 Arquillian Runner REST-Assured Integration Environment Resolver Normal REST-Assured Call helloworld: image: jonmorehouse/ping-pong ports: - "8080:8080" src/test/docker/docker-compose.yml
  • 52. @alexsotob Arquillian Cube DSL @RunWith(SpringRunner.class) @SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class) public class PingPongSpringBootTest { @ClassRule public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6") .withPortBinding(6379); @Autowired TestRestTemplate restTemplate; @Test public void should_get_data_from_redis() { } 52 Spring Boot Test Custom Initializer Container Definition public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext configurableApplicationContext) { EnvironmentTestUtils.addEnvironment("testcontainers", configurableApplicationContext.getEnvironment(), "spring.redis.host=" + redis.getIpAddress(), "spring.redis.port=" + redis.getBindPort(6379) ); Sets Container Environment
  • 54. @alexsotob Arquillian Kube @RunWith(Arquillian.class) public class HelloWorldTest { @ArquillianResource KubernetesClient client; @Named(“hello-world-service") @PortForward @ArquillianResource URL url; @Test public void testRunningPodStaysUp() throws Exception { assertThat(client).deployments().pods().isPodReadyForPeriod(); } } 54 Kubernetes Client URL to Access Service AssertJ Custom Assertions
  • 56. @alexsotob First attempt @Test public void should_find_composer_by_name() { // Given: clearDatabase(jdbcUri); insertComposersData(jdbcUri); ComposersRepository composersRepository = new ComposersRepository(); // When: Composer mozart = composersRepository.findComposerByName("Wolfgang Amadeus Mozart"); // Then: assertThat(mozart).returns("Wolfgang Amadeus Mozart", Composer::getName); } 56 Prepare Database Execute Query
  • 58. @alexsotob APE SQL example @Rule public ArquillianPersistenceRule arquillianPersistenceRule = new ArquillianPersistenceRule(); @DbUnit @ArquillianResource RdbmsPopulator rdbmsPopulator; @Before public void populateData() { // Given: rdbmsPopulator.forUri(jdbcUri).withDriver(Driver.class).withUsername("sa") .withPassword("").usingDataSet("composers.yml") .execute(); } 58 APE JUnit Rule (not necessary with Arquillian Runner) Set DBUnit usage Configure Connection and Dataset Populate composers: - id: 1 name: Wolfgang Amadeus Mozart birthdate: 27/1/1756 died: 5/12/1791
  • 59. @alexsotob APE SQL example @After public void clean_database() { // Given: rdbmsPopulator.forUri(jdbcUri).withDriver(Driver.class).withUsername("sa") .withPassword("").usingDataSet("composers.yml") .clean(); } 59 Clean After Test Clean Database
  • 61. @alexsotob61 Benefits of Arquillian APE > Boilerplate Code > Programmatic/Declarative @UsingDataSet/@ShouldMatchDataSet > SQL Support DBUnit and Flyway > RESTAPI Support Postman Collections > NoSQL Support MongoDB, Couchbase, CouchDB, Vault, Redis, Infinispan
  • 64. @alexsotob Smart Testing Maven Extension curl -sSL https://git.io/v5jy6 | bash 64 Installs extension mvn clean test -Dsmart.testing="new, changed, affected" Runs only new, changed and prod related tests mvn clean test -Dsmart.testing.mode=ordering -Dsmart.testing="new, changed, affected” Prioritize new, changed and prod related tests
  • 66. @alexsotob66 More about Smart Testing > Heuristics new, changed, affected, failed and categorized > Range of Commits Define where you want to look at > Configuration System Properties or YAML file (global or per module) > Jenkins Pipeline Shared Library Integrate with your CI/CD pipeline > Detection of none class changes @WatchFile("src/main/resources/META-INF/ > Surefire based Works with any kind of test that can be run in Surefire
  • 72. @alexsotob72 More about Diferencia > Comparison with, without noise detection, strict, subset > Formats supported JSON, Plain Text (automatic detection), HTTPS > Monitoring HTTP Status, Prometheus > Rest API Configure, Stats > Docker Image Ready to use in Kubernetes and OpenShift