SlideShare a Scribd company logo
1 of 49
Extreme Testing at kaChing From Commit to Production in 5 minutes Pascal-Louis Perez – @pascallouis Pascal-Louis Perez, kaChing Group Inc.
Engineering at kaChing TDD from day one Full regression suite runs in less than 3 minutes Deploy to production 30+ times a day People have written and launched new features during interview process Dedicated engineers to build testing frameworks Pascal-Louis Perez, kaChing Group Inc.
Testable Code Because… It allows quick iterations It makes it easier to scale the team It is more cost effective than debugging It obsoletes the need for functional QA It facilitates continuous refactoring, allowing the code to get better with age It attracts the right kind of engineers Pascal-Louis Perez, kaChing Group Inc.
High Level Classification Pascal-Louis Perez, kaChing Group Inc. Correctness Availability λ π
High Level Classification Pascal-Louis Perez, kaChing Group Inc. Correctness Availability ,[object Object]
 Bad: correct but unavailable systemλ π
High Level Classification Pascal-Louis Perez, kaChing Group Inc. Correctness Availability ,[object Object]
 Interactions (π): send an e-mail, store data in a db, RPC call
 In π implicit global mutable stateλ π
High Level Classification Pascal-Louis Perez, kaChing Group Inc. Correctness Availability λ ,[object Object]
 Input produces an output: just assert
 (Not  to be confused with implementation complexity!)π
High Level Classification Pascal-Louis Perez, kaChing Group Inc. Correctness Availability λ ,[object Object]
 Timing tests, benchmarking, …π
High Level Classification Pascal-Louis Perez, kaChing Group Inc. Correctness Availability λ π ,[object Object]
 Mocks, stubs, fakes,[object Object]
 End-to-end tests, regression test, performance lab(Find yourself a great architect!)
Think Outside the Box Pascal-Louis Perez, kaChing Group Inc. A A A A C C C C λ λ λ λ π π π π
Repository (or Client) Pattern Pascal-Louis Perez, kaChing Group Inc. @ImplementedBy(DbUserRepo.class)interfaceUserRepository {   User get(Id<User> id);} UserRepository repo = ...; User pascal = repo.get(Id.<User> of(8)); A A C C λ λ π π classDbUserRepoimplementsUserRepository {  // implementation}
Components Software composability is key to test-driven development Testable software abstracts the control flow; As such is functional by nature Pascal-Louis Perez, kaChing Group Inc.
Examples of Simple Tests Marshalling tests Dealing with time Equivalence tester Pascal-Louis Perez, kaChing Group Inc.
Marshalling tests Pascal-Louis Perez, kaChing Group Inc. C A  Fail fast Json.Object o = TwoLattes.createMarshaller(Trade.class).marshall(...); assertSameJson( object( string("id"), number(4), string("portfolioId"), NULL, string("trade"), string("interest"), string("date"), string("2008-07-06"), string("toDate"), string("2008-06-06"), string("fromDate"), string("2008-07-05"), string("longInterest"), number(56.43), string("shortInterest"), number(-0.81)),     o); λ π
Marshalling tests Pascal-Louis Perez, kaChing Group Inc. C A Json.Object o = TwoLattes.createMarshaller(Trade.class).marshall(...); assertSameJson( object( string("id"), number(4), string("portfolioId"), NULL, string("trade"), string("interest"), string("date"), string("2008-07-06"), string("toDate"), string("2008-06-06"), string("fromDate"), string("2008-07-05"), string("longInterest"), number(56.43), string("shortInterest"), number(-0.81)),     o);  Dedicated assertions λ π
Marshalling tests Pascal-Louis Perez, kaChing Group Inc. C A  Descriptive expectation Json.Object o = TwoLattes.createMarshaller(Trade.class).marshall(...); assertSameJson( object( string("id"), number(4), string("portfolioId"), NULL, string("trade"), string("interest"), string("date"), string("2008-07-06"), string("toDate"), string("2008-06-06"), string("fromDate"), string("2008-07-05"), string("longInterest"), number(56.43), string("shortInterest"), number(-0.81)),     o); λ π
Dealing with time Use clocks Provider<DateTime> Provider<LocalDate> Pass in now or today in business logic Pascal-Louis Perez, kaChing Group Inc. C A λ π
Time Logic Pascal-Louis Perez, kaChing Group Inc.  Time logic is easy     to test @VisibleForTesting <T> T provideCurrentOrHistorical( DateTime date, Provider<T> current, Provider<T> historical) { DateTimelastTradeDate = getLastTradeDate(); booleanisCurrent = date == null      || lastTradeDate == null       || date.compareTo(lastTradeDate) > 0; returnisCurrent ? current.get() : historical.get(); }
Time Logic Pascal-Louis Perez, kaChing Group Inc.  Higher-order functions @VisibleForTesting <T> T provideCurrentOrHistorical( DateTime date, Provider<T> current, Provider<T> historical) { DateTimelastTradeDate = getLastTradeDate(); booleanisCurrent = date == null      || lastTradeDate == null       || date.compareTo(lastTradeDate) > 0; returnisCurrent ? current.get() : historical.get(); }
Equivalence Tester Pascal-Louis Perez, kaChing Group Inc. C A Tests Reflexivity Symmetry Transitivity   hashCode consistency compareTo consistency  proper null handling EquivalenceTester.check( asList( newIsin("abCdEFgHiJK3“), newIsin("ABCDEFGHIJK3“), newIsin(“abCDefGHIJK3")), asList( newIsin("AU0000XVGZA3"), newIsin("AU0000XVGZA3"))); λ π
Rationale for Database Testing Accessing the database correctly O/R properly configured and used Hand written queries Optimistic concurrency Pascal-Louis Perez, kaChing Group Inc.
JDBC Pascal-Louis Perez, kaChing Group Inc.  Global static state DriverManager.registerDriver(neworg.gjt.mm.mysql.Driver());  Connection conn = DriverManager.getConnection("jdbc:..."); PreparedStatementst = conn.prepareStatement("select ..."); st.setString(1, "..."); ResultSetrs = st.executeQuery(); while (rs.next()) { // work  } rs.close(); st.close(); conn.close();
JDBC Pascal-Louis Perez, kaChing Group Inc. DriverManager.registerDriver(neworg.gjt.mm.mysql.Driver());  Connection conn = DriverManager.getConnection("jdbc:..."); PreparedStatementst = conn.prepareStatement("select ..."); st.setString(1, "..."); ResultSetrs = st.executeQuery(); while (rs.next()) { // work  } rs.close(); st.close(); conn.close();  Low level, stateful API, wide scoping
JDBC Pascal-Louis Perez, kaChing Group Inc. DriverManager.registerDriver(neworg.gjt.mm.mysql.Driver());  Connection conn = DriverManager.getConnection("jdbc:..."); PreparedStatementst = conn.prepareStatement("select ..."); st.setString(1, "..."); ResultSetrs = st.executeQuery(); while (rs.next()) { // work  } rs.close(); st.close(); conn.close();  Resources hell
Hibernate Pascal-Louis Perez, kaChing Group Inc.  Global state SessionFactory factory = ...; Session session = factory.openSession(); Transaction tx = session.beginTransaction();List<User> users = session    .createQuery("from User where ...")    .list(); for (User user : users) { // work  } tx.commit(); session.close();
Hibernate Pascal-Louis Perez, kaChing Group Inc.  High-level API SessionFactory factory = ...; Session session = factory.openSession(); Transaction tx = session.beginTransaction();List<User> users = session    .createQuery("from User where ...")    .list(); for (User user : users) { // work  } tx.commit(); session.close();
Hibernate Pascal-Louis Perez, kaChing Group Inc. SessionFactory factory = ...; Session session = factory.openSession(); Transaction tx = session.beginTransaction();List<User> users = session    .createQuery("from User where ...")    .list(); for (User user : users) { // work  } tx.commit(); session.close();  Resources hell
Transacter Pascal-Louis Perez, kaChing Group Inc.  Global state Transactertransacter = ...; transacter.execute(newWithSession() { publicvoid run(Session session) {    List<User> users = ...; for (User user : users) { // work     }   } });
Transacter Pascal-Louis Perez, kaChing Group Inc.  High-level API, no resources Transactertransacter = ...; transacter.execute(newWithSession() { publicvoid run(Session session) {    List<User> users = ...; for (User user : users) { // work     }   } });
Transacter Pascal-Louis Perez, kaChing Group Inc. Transactertransacter = ...; transacter.execute(newWithSession() { publicvoid run(Session session) {    List<User> users = ...; for (User user : users) { // work     }   } });  Lexical scoping
Database Testing is Hard Complex to set up Schema installation Requires data to be loaded Developer must have proper environment Pascal-Louis Perez, kaChing Group Inc. : PersistenceTestRunnerü : O/R Mapping ü : Fixtures, DbUnitü : in-memory DBs (HSQLDB, Connector/MXJ) ü
PersistenceTestRunner Pascal-Louis Perez, kaChing Group Inc. C A  Declarative setup @RunWith(PersistenceTestRunner.class) @PersistentEntities({Item.class, Note.class}) publicclassExamplePersistentTest { @Test publicvoid example1(Transactertransacter) { // work   } @Test publicvoid example2() { // work   } } λ π
PersistenceTestRunner Pascal-Louis Perez, kaChing Group Inc. C A @RunWith(PersistenceTestRunner.class) @PersistentEntities({Item.class, Note.class}) publicclassExamplePersistentTest { @Test publicvoid example1(Transactertransacter) { // work   } @Test publicvoid example2() { // work   } }  Lexical scoping λ π
PersistenceTestRunner Pascal-Louis Perez, kaChing Group Inc. C A @RunWith(PersistenceTestRunner.class) @PersistentEntities({Item.class, Note.class}) publicclassExamplePersistentTest { @Test publicvoid example1(Transactertransacter) { // work   } @Test publicvoid example2() { // work   } } λ  RuntimeException π
PersistenceTestRunner Pascal-Louis Perez, kaChing Group Inc. C A @RunWith(PersistenceTestRunner.class) @PersistentEntities({Item.class, Note.class}) publicclassExamplePersistentTest { @Test publicvoid example1(Transactertransacter) { // work   } @Test publicvoid example2() { // work   } } λ π  Non-persistent tests run as usual
Testing Interactions (I/O, …) Implicit global state Many cases HTTP GET: succeed, fail to connect, connection closed before headers are read, … Sending e-mail: succeed, connection lost after HELO, … Sequencing is crucial Pascal-Louis Perez, kaChing Group Inc. C A λ π
Testing the Transacter (success) Pascal-Louis Perez, kaChing Group Inc. C A  Mocking finalWithSessionwithSession = mockery.mock(WithSession.class); mockery.checking(new Expectations() {{   one(sessionFactory).openSession();       will(returnValue(session)); inSequence(execution);   one(session).connection(); will(...); inSequence(...);   one(connection).setReadOnly(with(equal(false))); ...   one(connection).setAutoCommit(with(equal(false))); ...   one(session).beginTransaction(); inSequence(...);  ... }}); transacter.execute(withSession); mockery.assertIsSatisfied(); λ π
Testing the Transacter (success) Pascal-Louis Perez, kaChing Group Inc. C A finalWithSessionwithSession = mockery.mock(WithSession.class); mockery.checking(new Expectations() {{   one(sessionFactory).openSession();       will(returnValue(session)); inSequence(execution);   one(session).connection(); will(...); inSequence(...);   one(connection).setReadOnly(with(equal(false))); ...   one(connection).setAutoCommit(with(equal(false))); ...   one(session).beginTransaction(); inSequence(...);  ... }}); transacter.execute(withSession); mockery.assertIsSatisfied();  Interactions are scripted λ π
Testing the Transacter (failure) Pascal-Louis Perez, kaChing Group Inc.  Failure is controlled C mockery.checking(new Expectations() {{   one(sessionFactory).openSession();  ...   one(connection).setReadOnly(with(equal(false)));       will(throwException(exception)); inSequence(execution);   one(session).close(); inSequence(execution); }}); try { transacter.execute(withSession); fail(); } catch (RuntimeException e) { assertTrue(e == exception); }mockery.assertIsSatisfied(); A λ π
Testing the Transacter (failure) Pascal-Louis Perez, kaChing Group Inc. C mockery.checking(new Expectations() {{   one(sessionFactory).openSession();  ...   one(connection).setReadOnly(with(equal(false)));       will(throwException(exception)); inSequence(execution);   one(session).close(); inSequence(execution); }}); try { transacter.execute(withSession); fail(); } catch (RuntimeException e) { assertTrue(e == exception); }mockery.assertIsSatisfied(); A  Exact  same object (correct bubbling) λ π

More Related Content

More from Pascal-Louis Perez

Products’ Love Story with Biz
Products’ Love Story with BizProducts’ Love Story with Biz
Products’ Love Story with BizPascal-Louis Perez
 
How to Send a Receipt, Topics in Concurrency and Distributed Systems
How to Send a Receipt, Topics in Concurrency and Distributed SystemsHow to Send a Receipt, Topics in Concurrency and Distributed Systems
How to Send a Receipt, Topics in Concurrency and Distributed SystemsPascal-Louis Perez
 
Developing an Immune System — The Hard and Soft Skills required to avoid Outages
Developing an Immune System — The Hard and Soft Skills required to avoid OutagesDeveloping an Immune System — The Hard and Soft Skills required to avoid Outages
Developing an Immune System — The Hard and Soft Skills required to avoid OutagesPascal-Louis Perez
 
SLL Conf - Continuous Deployment
SLL Conf - Continuous DeploymentSLL Conf - Continuous Deployment
SLL Conf - Continuous DeploymentPascal-Louis Perez
 
Alchemist Startup Primer - Lean Development Practices
Alchemist Startup Primer - Lean Development PracticesAlchemist Startup Primer - Lean Development Practices
Alchemist Startup Primer - Lean Development PracticesPascal-Louis Perez
 
Applying Compiler Techniques to Iterate At Blazing Speed
Applying Compiler Techniques to Iterate At Blazing SpeedApplying Compiler Techniques to Iterate At Blazing Speed
Applying Compiler Techniques to Iterate At Blazing SpeedPascal-Louis Perez
 
Iterate Like a Whirling Dervish
Iterate Like a Whirling DervishIterate Like a Whirling Dervish
Iterate Like a Whirling DervishPascal-Louis Perez
 
Xignite's Dedicate kaChing Api
Xignite's Dedicate kaChing ApiXignite's Dedicate kaChing Api
Xignite's Dedicate kaChing ApiPascal-Louis Perez
 
Add (Syntactic) Sugar To Your Java
Add (Syntactic) Sugar To Your JavaAdd (Syntactic) Sugar To Your Java
Add (Syntactic) Sugar To Your JavaPascal-Louis Perez
 

More from Pascal-Louis Perez (14)

Products’ Love Story with Biz
Products’ Love Story with BizProducts’ Love Story with Biz
Products’ Love Story with Biz
 
How to Send a Receipt, Topics in Concurrency and Distributed Systems
How to Send a Receipt, Topics in Concurrency and Distributed SystemsHow to Send a Receipt, Topics in Concurrency and Distributed Systems
How to Send a Receipt, Topics in Concurrency and Distributed Systems
 
Corporate Finance Primer
Corporate Finance PrimerCorporate Finance Primer
Corporate Finance Primer
 
Developing an Immune System — The Hard and Soft Skills required to avoid Outages
Developing an Immune System — The Hard and Soft Skills required to avoid OutagesDeveloping an Immune System — The Hard and Soft Skills required to avoid Outages
Developing an Immune System — The Hard and Soft Skills required to avoid Outages
 
SLL Conf - Continuous Deployment
SLL Conf - Continuous DeploymentSLL Conf - Continuous Deployment
SLL Conf - Continuous Deployment
 
Alchemist Startup Primer - Lean Development Practices
Alchemist Startup Primer - Lean Development PracticesAlchemist Startup Primer - Lean Development Practices
Alchemist Startup Primer - Lean Development Practices
 
Database compatibility
Database compatibilityDatabase compatibility
Database compatibility
 
Applying Compiler Techniques to Iterate At Blazing Speed
Applying Compiler Techniques to Iterate At Blazing SpeedApplying Compiler Techniques to Iterate At Blazing Speed
Applying Compiler Techniques to Iterate At Blazing Speed
 
Iterate Like a Whirling Dervish
Iterate Like a Whirling DervishIterate Like a Whirling Dervish
Iterate Like a Whirling Dervish
 
Extreme Testing at kaChing
Extreme Testing at kaChingExtreme Testing at kaChing
Extreme Testing at kaChing
 
Type Checking JavaScript
Type Checking JavaScriptType Checking JavaScript
Type Checking JavaScript
 
Xignite's Dedicate kaChing Api
Xignite's Dedicate kaChing ApiXignite's Dedicate kaChing Api
Xignite's Dedicate kaChing Api
 
Add (Syntactic) Sugar To Your Java
Add (Syntactic) Sugar To Your JavaAdd (Syntactic) Sugar To Your Java
Add (Syntactic) Sugar To Your Java
 
kaChing's API garage event
kaChing's API garage eventkaChing's API garage event
kaChing's API garage event
 

Recently uploaded

DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 

Recently uploaded (20)

DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 

Extreme Testing at kaChing: From Commit to Production in 5 Minutes

  • 1. Extreme Testing at kaChing From Commit to Production in 5 minutes Pascal-Louis Perez – @pascallouis Pascal-Louis Perez, kaChing Group Inc.
  • 2. Engineering at kaChing TDD from day one Full regression suite runs in less than 3 minutes Deploy to production 30+ times a day People have written and launched new features during interview process Dedicated engineers to build testing frameworks Pascal-Louis Perez, kaChing Group Inc.
  • 3.
  • 4. Testable Code Because… It allows quick iterations It makes it easier to scale the team It is more cost effective than debugging It obsoletes the need for functional QA It facilitates continuous refactoring, allowing the code to get better with age It attracts the right kind of engineers Pascal-Louis Perez, kaChing Group Inc.
  • 5. High Level Classification Pascal-Louis Perez, kaChing Group Inc. Correctness Availability λ π
  • 6.
  • 7. Bad: correct but unavailable systemλ π
  • 8.
  • 9. Interactions (π): send an e-mail, store data in a db, RPC call
  • 10. In π implicit global mutable stateλ π
  • 11.
  • 12. Input produces an output: just assert
  • 13. (Not to be confused with implementation complexity!)π
  • 14.
  • 15. Timing tests, benchmarking, …π
  • 16.
  • 17.
  • 18. End-to-end tests, regression test, performance lab(Find yourself a great architect!)
  • 19. Think Outside the Box Pascal-Louis Perez, kaChing Group Inc. A A A A C C C C λ λ λ λ π π π π
  • 20. Repository (or Client) Pattern Pascal-Louis Perez, kaChing Group Inc. @ImplementedBy(DbUserRepo.class)interfaceUserRepository { User get(Id<User> id);} UserRepository repo = ...; User pascal = repo.get(Id.<User> of(8)); A A C C λ λ π π classDbUserRepoimplementsUserRepository { // implementation}
  • 21. Components Software composability is key to test-driven development Testable software abstracts the control flow; As such is functional by nature Pascal-Louis Perez, kaChing Group Inc.
  • 22. Examples of Simple Tests Marshalling tests Dealing with time Equivalence tester Pascal-Louis Perez, kaChing Group Inc.
  • 23. Marshalling tests Pascal-Louis Perez, kaChing Group Inc. C A  Fail fast Json.Object o = TwoLattes.createMarshaller(Trade.class).marshall(...); assertSameJson( object( string("id"), number(4), string("portfolioId"), NULL, string("trade"), string("interest"), string("date"), string("2008-07-06"), string("toDate"), string("2008-06-06"), string("fromDate"), string("2008-07-05"), string("longInterest"), number(56.43), string("shortInterest"), number(-0.81)), o); λ π
  • 24. Marshalling tests Pascal-Louis Perez, kaChing Group Inc. C A Json.Object o = TwoLattes.createMarshaller(Trade.class).marshall(...); assertSameJson( object( string("id"), number(4), string("portfolioId"), NULL, string("trade"), string("interest"), string("date"), string("2008-07-06"), string("toDate"), string("2008-06-06"), string("fromDate"), string("2008-07-05"), string("longInterest"), number(56.43), string("shortInterest"), number(-0.81)), o);  Dedicated assertions λ π
  • 25. Marshalling tests Pascal-Louis Perez, kaChing Group Inc. C A  Descriptive expectation Json.Object o = TwoLattes.createMarshaller(Trade.class).marshall(...); assertSameJson( object( string("id"), number(4), string("portfolioId"), NULL, string("trade"), string("interest"), string("date"), string("2008-07-06"), string("toDate"), string("2008-06-06"), string("fromDate"), string("2008-07-05"), string("longInterest"), number(56.43), string("shortInterest"), number(-0.81)), o); λ π
  • 26. Dealing with time Use clocks Provider<DateTime> Provider<LocalDate> Pass in now or today in business logic Pascal-Louis Perez, kaChing Group Inc. C A λ π
  • 27. Time Logic Pascal-Louis Perez, kaChing Group Inc.  Time logic is easy to test @VisibleForTesting <T> T provideCurrentOrHistorical( DateTime date, Provider<T> current, Provider<T> historical) { DateTimelastTradeDate = getLastTradeDate(); booleanisCurrent = date == null || lastTradeDate == null || date.compareTo(lastTradeDate) > 0; returnisCurrent ? current.get() : historical.get(); }
  • 28. Time Logic Pascal-Louis Perez, kaChing Group Inc.  Higher-order functions @VisibleForTesting <T> T provideCurrentOrHistorical( DateTime date, Provider<T> current, Provider<T> historical) { DateTimelastTradeDate = getLastTradeDate(); booleanisCurrent = date == null || lastTradeDate == null || date.compareTo(lastTradeDate) > 0; returnisCurrent ? current.get() : historical.get(); }
  • 29. Equivalence Tester Pascal-Louis Perez, kaChing Group Inc. C A Tests Reflexivity Symmetry Transitivity  hashCode consistency compareTo consistency  proper null handling EquivalenceTester.check( asList( newIsin("abCdEFgHiJK3“), newIsin("ABCDEFGHIJK3“), newIsin(“abCDefGHIJK3")), asList( newIsin("AU0000XVGZA3"), newIsin("AU0000XVGZA3"))); λ π
  • 30. Rationale for Database Testing Accessing the database correctly O/R properly configured and used Hand written queries Optimistic concurrency Pascal-Louis Perez, kaChing Group Inc.
  • 31. JDBC Pascal-Louis Perez, kaChing Group Inc.  Global static state DriverManager.registerDriver(neworg.gjt.mm.mysql.Driver()); Connection conn = DriverManager.getConnection("jdbc:..."); PreparedStatementst = conn.prepareStatement("select ..."); st.setString(1, "..."); ResultSetrs = st.executeQuery(); while (rs.next()) { // work } rs.close(); st.close(); conn.close();
  • 32. JDBC Pascal-Louis Perez, kaChing Group Inc. DriverManager.registerDriver(neworg.gjt.mm.mysql.Driver()); Connection conn = DriverManager.getConnection("jdbc:..."); PreparedStatementst = conn.prepareStatement("select ..."); st.setString(1, "..."); ResultSetrs = st.executeQuery(); while (rs.next()) { // work } rs.close(); st.close(); conn.close();  Low level, stateful API, wide scoping
  • 33. JDBC Pascal-Louis Perez, kaChing Group Inc. DriverManager.registerDriver(neworg.gjt.mm.mysql.Driver()); Connection conn = DriverManager.getConnection("jdbc:..."); PreparedStatementst = conn.prepareStatement("select ..."); st.setString(1, "..."); ResultSetrs = st.executeQuery(); while (rs.next()) { // work } rs.close(); st.close(); conn.close();  Resources hell
  • 34. Hibernate Pascal-Louis Perez, kaChing Group Inc.  Global state SessionFactory factory = ...; Session session = factory.openSession(); Transaction tx = session.beginTransaction();List<User> users = session .createQuery("from User where ...") .list(); for (User user : users) { // work } tx.commit(); session.close();
  • 35. Hibernate Pascal-Louis Perez, kaChing Group Inc.  High-level API SessionFactory factory = ...; Session session = factory.openSession(); Transaction tx = session.beginTransaction();List<User> users = session .createQuery("from User where ...") .list(); for (User user : users) { // work } tx.commit(); session.close();
  • 36. Hibernate Pascal-Louis Perez, kaChing Group Inc. SessionFactory factory = ...; Session session = factory.openSession(); Transaction tx = session.beginTransaction();List<User> users = session .createQuery("from User where ...") .list(); for (User user : users) { // work } tx.commit(); session.close();  Resources hell
  • 37. Transacter Pascal-Louis Perez, kaChing Group Inc.  Global state Transactertransacter = ...; transacter.execute(newWithSession() { publicvoid run(Session session) { List<User> users = ...; for (User user : users) { // work } } });
  • 38. Transacter Pascal-Louis Perez, kaChing Group Inc.  High-level API, no resources Transactertransacter = ...; transacter.execute(newWithSession() { publicvoid run(Session session) { List<User> users = ...; for (User user : users) { // work } } });
  • 39. Transacter Pascal-Louis Perez, kaChing Group Inc. Transactertransacter = ...; transacter.execute(newWithSession() { publicvoid run(Session session) { List<User> users = ...; for (User user : users) { // work } } });  Lexical scoping
  • 40. Database Testing is Hard Complex to set up Schema installation Requires data to be loaded Developer must have proper environment Pascal-Louis Perez, kaChing Group Inc. : PersistenceTestRunnerü : O/R Mapping ü : Fixtures, DbUnitü : in-memory DBs (HSQLDB, Connector/MXJ) ü
  • 41. PersistenceTestRunner Pascal-Louis Perez, kaChing Group Inc. C A  Declarative setup @RunWith(PersistenceTestRunner.class) @PersistentEntities({Item.class, Note.class}) publicclassExamplePersistentTest { @Test publicvoid example1(Transactertransacter) { // work } @Test publicvoid example2() { // work } } λ π
  • 42. PersistenceTestRunner Pascal-Louis Perez, kaChing Group Inc. C A @RunWith(PersistenceTestRunner.class) @PersistentEntities({Item.class, Note.class}) publicclassExamplePersistentTest { @Test publicvoid example1(Transactertransacter) { // work } @Test publicvoid example2() { // work } }  Lexical scoping λ π
  • 43. PersistenceTestRunner Pascal-Louis Perez, kaChing Group Inc. C A @RunWith(PersistenceTestRunner.class) @PersistentEntities({Item.class, Note.class}) publicclassExamplePersistentTest { @Test publicvoid example1(Transactertransacter) { // work } @Test publicvoid example2() { // work } } λ  RuntimeException π
  • 44. PersistenceTestRunner Pascal-Louis Perez, kaChing Group Inc. C A @RunWith(PersistenceTestRunner.class) @PersistentEntities({Item.class, Note.class}) publicclassExamplePersistentTest { @Test publicvoid example1(Transactertransacter) { // work } @Test publicvoid example2() { // work } } λ π  Non-persistent tests run as usual
  • 45. Testing Interactions (I/O, …) Implicit global state Many cases HTTP GET: succeed, fail to connect, connection closed before headers are read, … Sending e-mail: succeed, connection lost after HELO, … Sequencing is crucial Pascal-Louis Perez, kaChing Group Inc. C A λ π
  • 46. Testing the Transacter (success) Pascal-Louis Perez, kaChing Group Inc. C A  Mocking finalWithSessionwithSession = mockery.mock(WithSession.class); mockery.checking(new Expectations() {{ one(sessionFactory).openSession(); will(returnValue(session)); inSequence(execution); one(session).connection(); will(...); inSequence(...); one(connection).setReadOnly(with(equal(false))); ... one(connection).setAutoCommit(with(equal(false))); ... one(session).beginTransaction(); inSequence(...); ... }}); transacter.execute(withSession); mockery.assertIsSatisfied(); λ π
  • 47. Testing the Transacter (success) Pascal-Louis Perez, kaChing Group Inc. C A finalWithSessionwithSession = mockery.mock(WithSession.class); mockery.checking(new Expectations() {{ one(sessionFactory).openSession(); will(returnValue(session)); inSequence(execution); one(session).connection(); will(...); inSequence(...); one(connection).setReadOnly(with(equal(false))); ... one(connection).setAutoCommit(with(equal(false))); ... one(session).beginTransaction(); inSequence(...); ... }}); transacter.execute(withSession); mockery.assertIsSatisfied();  Interactions are scripted λ π
  • 48. Testing the Transacter (failure) Pascal-Louis Perez, kaChing Group Inc.  Failure is controlled C mockery.checking(new Expectations() {{ one(sessionFactory).openSession(); ... one(connection).setReadOnly(with(equal(false))); will(throwException(exception)); inSequence(execution); one(session).close(); inSequence(execution); }}); try { transacter.execute(withSession); fail(); } catch (RuntimeException e) { assertTrue(e == exception); }mockery.assertIsSatisfied(); A λ π
  • 49. Testing the Transacter (failure) Pascal-Louis Perez, kaChing Group Inc. C mockery.checking(new Expectations() {{ one(sessionFactory).openSession(); ... one(connection).setReadOnly(with(equal(false))); will(throwException(exception)); inSequence(execution); one(session).close(); inSequence(execution); }}); try { transacter.execute(withSession); fail(); } catch (RuntimeException e) { assertTrue(e == exception); }mockery.assertIsSatisfied(); A  Exact same object (correct bubbling) λ π
  • 50. Testing the Transacter (failure) Pascal-Louis Perez, kaChing Group Inc. C mockery.checking(new Expectations() {{ one(sessionFactory).openSession(); ... one(connection).setReadOnly(with(equal(false))); will(throwException(exception)); inSequence(execution); one(session).close(); inSequence(execution); }}); try { transacter.execute(withSession); fail(); } catch (RuntimeException e) { assertTrue(e == exception); }mockery.assertIsSatisfied(); A  Unreachable program point λ π
  • 51. Meta Tests Cross domain tests to sweep the codebase, exactly like static analysis Catch common mistakes Distracted developers Bad APIs New hires learning conventions Pascal-Louis Perez, kaChing Group Inc.
  • 52. Dependency Test Declare software dependencies Controls layering of application Simpler and more flexible than different compilation units Can guarantee that certain APIs are not used directly Patched Jdepend to parse annotations Pascal-Louis Perez, kaChing Group Inc. C A λ π
  • 53. Dependency Test Pascal-Louis Perez, kaChing Group Inc. dependencies.forPackages( "com.kaching.*" ). check("com.kaching.supermap").mayDependOn( "com.kaching.platform.guice", "org.apache.commons.lang", "voldemort.*", "org.kohsuke.args4j" ). assertIsVerified(jDepend.getPackages());
  • 54. Bad Code Test Enforce conventions Gotchas, bad APIs E.g. System.out.println E.g. java.net.URL Code reviews Design patterns, custom APIs, etc. Enforce conventions: automate this! Pascal-Louis Perez, kaChing Group Inc. C A λ π
  • 55. Bad Code Test Pascal-Louis Perez, kaChing Group Inc. @RunWith(BadCodeSnippetsRunner.class) @CodeSnippets({ @Check(paths = "src/com/kaching", snippets = { // no uses of java.net.URL @Snippet(value = "bjava.net.URLb", exceptions = { "src/com/kaching/...", "src/com/kaching/..." }), // never call default super constructor @Snippet("super()") })})class MyBadCodeSnippetsTest {
  • 56. Key Takeaways Invest in your tests, and testing frameworks Design patterns to separate concerns Components TDD pushes towards functional techniques We’re recruiting jobs@kaching.com More http://eng.kaching.com Pascal-Louis Perez, kaChing Group Inc.

Editor's Notes

  1. Title: Extreme Testing at kaChing: From Commit to Production in 5 Minutes.Abstract: At kaChing (www.kaching.com), we are on a 5-minute commit-to-production cycle. We have adopted continuous deployment as a way of life and as the natural next step to continuous integration.In this talk, I will present how we achieved this extreme iteration cycle. We will start at a very high level and look at the two fundamental aspects of software: transformations, which are stateless data operations, and interactions, which deal with state (such as a database, or an e-mail server). With this background we will delve into practical matters and survey kaChing&apos;s testing infrastructure by motivating each category of tests with different kind of problems often encountered. Finally, we will look at software patterns that lend themselves to testing and achieving separation of concerns allowing unparalleled software composability.(This talk will focus on a Java environment even though the discussion will be largely applicable.) Bio: Pascal-Louis Perez came to kaChing from Google, where he worked on the creation of a JavaScript-to-JavaScript complier. At Google, Mr. Perez also was on the ECMA committee, working towards the standardization of ECMAScript 4. An entrepreneur since youth, Mr. Perez created his first company at the age of 16. He also co-authored &quot;Vocation Createur&quot; (Editions du Tricorne, 2004), a book portraying entrepreneurs. Mr. Perez holds a bachelor&apos;s degree in science from the Federal Institut of Technology Lausanne and a master&apos;s degree with distinction in research from Stanford University.
  2. -Scale the team: add features without adding engineers to support and maintain these features. This requires “production tests” a.k.a. monitoring.-Debugging: debugging live servers in a production environment!-At kaChing, we’ve never spent $1 on QA-Not all engineers are excited by a test-driven environment. Some are happy with “tests” taking “only” 5 hours to run.
  3. -correctness: an incorrect but available system is useless- availability: a correct system you cannot use is useless-lambda: congruence-pi: side effects, not congruent, while semantics
  4. -Speed is an availability concern. I want a response in 1 second, if the system is too slow my response will not be available.-Scale is an availability concern. If many people start using your system, it might become unavailable.
  5. -lambda &amp; correctness: extremely easy to test. Input -&gt; output. This does not mean it is easy to implement! Think about a compiler-lambda &amp; availability: can only be CPU bound, trivial.
  6. -lambda &amp; correctness: extremely easy to test. Input -&gt; output. This does not mean it is easy to implement! Think about a compiler-lambda &amp; availability: can only be CPU bound, trivial.
  7. -lambda &amp; correctness: extremely easy to test. Input -&gt; output. This does not mean it is easy to implement! Think about a compiler-lambda &amp; availability: can only be CPU bound, trivial.
  8. -lambda &amp; correctness: extremely easy to test. Input -&gt; output. This does not mean it is easy to implement! Think about a compiler-lambda &amp; availability: can only be CPU bound, trivial.
  9. When using the repository pattern, use stubs!
  10. JSON is used for most RPCs at kaChing, the JsonMarshaller is a nice library that converts POJOs to and from JSONWhen desgning APIs for testability, give strong guarantees such that really small test are very meaningful
  11. JSON is used for most RPCs at kaChing, the JsonMarshaller is a nice library that converts POJOs to and from JSONWhen desgning APIs for testability, give strong guarantees such that really small test are very meaningful
  12. JSON is used for most RPCs at kaChing, the JsonMarshaller is a nice library that converts POJOs to and from JSONWhen desgning APIs for testability, give strong guarantees such that really small test are very meaningful
  13. Checks for reflexivity (a equals a)Checks for transitivity (a = b and b = c =&gt; a = c)Checks for symmetry (a = b =&gt; b = a)Makes sure hashCode is consistent for all equal objects
  14. Before we look into database testing, I want to give a glance of what is the low level pieces of database connectivity in Java.As we can see here, we interact with STATIC global state (registering the driver) and then take advantage of this when we open the connection. Much worse from a testing perspective than global state.I’m leaving out the try/catch/finally hell for readability but please not that ALL calls can throw, can that three resources must be properly closed.Static global stateStateful, complex API, scoping is too largeClose, close, close. Try/catch/finally hell.
  15. Before we look into database testing, I want to give a glance of what is the low level pieces of database connectivity in Java.As we can see here, we interact with STATIC global state (registering the driver) and then take advantage of this when we open the connection. Much worse from a testing perspective than global state.I’m leaving out the try/catch/finally hell for readability but please not that ALL calls can throw, can that three resources must be properly closed.Static global stateStateful, complex API, scoping is too largeClose, close, close. Try/catch/finally hell.
  16. Before we look into database testing, I want to give a glance of what is the low level pieces of database connectivity in Java.As we can see here, we interact with STATIC global state (registering the driver) and then take advantage of this when we open the connection. Much worse from a testing perspective than global state.I’m leaving out the try/catch/finally hell for readability but please not that ALL calls can throw, can that three resources must be properly closed.Static global stateStateful, complex API, scoping is too largeClose, close, close. Try/catch/finally hell.
  17. Hibernate is just one example of many O/R mapping tools available. Hibernate can be very high level, or very low level (nice JDBC wrapper). Examples HQL, object graph traversals, raw queries, back to JDBC with access to connection (e.g. to do very efficient bulk inserts).Global state (staticness is hidden)Simple API, not staful, still scoping issuesCommit, close. Try/catch/finally hell.
  18. Hibernate is just one example of many O/R mapping tools available. Hibernate can be very high level, or very low level (nice JDBC wrapper). Examples HQL, object graph traversals, raw queries, back to JDBC with access to connection (e.g. to do very efficient bulk inserts).Global state (staticness is hidden)Simple API, not staful, still scoping issuesCommit, close. Try/catch/finally hell.
  19. Hibernate is just one example of many O/R mapping tools available. Hibernate can be very high level, or very low level (nice JDBC wrapper). Examples HQL, object graph traversals, raw queries, back to JDBC with access to connection (e.g. to do very efficient bulk inserts).Global state (staticness is hidden)Simple API, not staful, still scoping issuesCommit, close. Try/catch/finally hell.
  20. Global stateSimple API, scoping is lexical. Resources are automatically handled by the framework.Excellent logging in error cases: mismatch between runtime exception and checked exception makes it hard to decipher why something failed
  21. Global stateSimple API, scoping is lexical. Resources are automatically handled by the framework.Excellent logging in error cases: mismatch between runtime exception and checked exception makes it hard to decipher why something failed
  22. Global stateSimple API, scoping is lexical. Resources are automatically handled by the framework.Excellent logging in error cases: mismatch between runtime exception and checked exception makes it hard to decipher why something failed
  23. Setup and schema installation is done automatically by the runner with the help of Hibernate’s DDL support. Easy to have fixture helpers taking a transacter as argument and putting data, runner has a hook for DbUnit files.Framework can ensure isolation and run tests blazingly fast (optimise schema creation, cleanup, etc.)Tests can easily be wired to run on different kinds of databases on the side of the default
  24. Setup and schema installation is done automatically by the runner with the help of Hibernate’s DDL support. Easy to have fixture helpers taking a transacter as argument and putting data, runner has a hook for DbUnit files.Framework can ensure isolation and run tests blazingly fast (optimise schema creation, cleanup, etc.)Tests can easily be wired to run on different kinds of databases on the side of the default
  25. Setup and schema installation is done automatically by the runner with the help of Hibernate’s DDL support. Easy to have fixture helpers taking a transacter as argument and putting data, runner has a hook for DbUnit files.Framework can ensure isolation and run tests blazingly fast (optimise schema creation, cleanup, etc.)Tests can easily be wired to run on different kinds of databases on the side of the default
  26. Setup and schema installation is done automatically by the runner with the help of Hibernate’s DDL support. Easy to have fixture helpers taking a transacter as argument and putting data, runner has a hook for DbUnit files.Framework can ensure isolation and run tests blazingly fast (optimise schema creation, cleanup, etc.)Tests can easily be wired to run on different kinds of databases on the side of the default