SlideShare a Scribd company logo
Kevin Brockhoff
Deliver Faster with
BDD/TDD
Designing Automated Tests
That Don’t Suck
–Uncle Bob
“The only way to go fast is to go well.”
Accelerate
❖ Software Delivery Performance Metrics That Matter
❖ Deployment Frequency
❖ Lead Time for Changes
❖ Mean Time To Restore (MTTR)
❖ Change Failure Rate
Accelerate: The Science of Lean Software and DevOps: Building and Scaling High Performing Technology Organizations
By Nicole Forsgren PhD, Jez Humble, and Gene Kim
Fast vs Quality
Annual State of DevOps Report sponsored by Puppet Labs
–Jerry Weinberg
“A system is never finished being developed until
it ceases to be used.”
–John Woods
“Always code as if the guy who ends up
maintaining your code will be a violent
psychopath who knows where you live.”
Maintenance 75% of TCO
–Michael Feathers
“Legacy code is code without tests.”
Deliver Valuable Software Faster
Problem How TDD/BDD Can Help
Long QA Test Cycles Identify incorrect behavior before release to QA
Rework
Identify incorrect behavior during initial
development so can fix when most familiar with the
code
Disproportionate time spent studying code before
making small change
Confidence tests will identify if change will break
other behavior
Slow and difficult client development Verify API usability and tests as documentation
Slow and difficult to extend and/or add features
Testability strongly correlated with flexibility and
extensibility
–Chinese proverb
“To be uncertain is to be uncomfortable, but to be
certain is to be ridiculous.”
Testing Pyramid
Testing pyramid concept introduced in
Succeeding with Agile by Mike Cohn
End-to-End Tests
❖ Developers like it because it offloads
most, if not all, of the testing to others.
❖ Managers and decision-makers like it
because tests that simulate real user
scenarios can help them easily
determine how a failing test would
impact the user.
❖ Testers like it because they often
worry about missing a bug or writing
a test that does not verify real-world
behavior; writing tests from the user's
perspective often avoids both
problems and gives the tester a greater
sense of accomplishment.
Days Left Pass % Notes
1 5%
Everything is broken! Signing in to the service is
broken. Almost all tests sign in a user, so almost
all tests failed.
0 4%
A partner team we rely on deployed a bad build to
their testing environment yesterday.
-1 54%
A dev broke the save scenario yesterday (or the
day before?). Half the tests save a document at
some point in time. Devs spent most of the day
determining if it's a frontend bug or a backend
-2 54%
It's a frontend bug, devs spent half of today
figuring out where.
-3 54%
A bad fix was checked in yesterday. The mistake
was pretty easy to spot, though, and a correct fix
was checked in today.
-4 1%
Hardware failures occurred in the lab for our
testing environment.
-5 84%
Many small bugs hiding behind the big bugs (e.g.,
sign-in broken, save broken). Still working on the
small bugs.
-6 87%
We should be above 90%, but are not for some
reason.
-7 89.54%
(Rounds up to 90%, close enough.) No fixes were
checked in yesterday, so the tests must have
been flaky yesterday.
In Theory In Practice
Source: Mike Wacker on Google Testing Blog
Test Tooling
–Fred Brooks
“The hardest part of building a software system is
deciding precisely what to build... No other part of
the work so cripples the resulting system if done
wrong. No other part is more difficult to rectify
later”
Java Unit Test Frameworks
Strong Points Migrating from JUnit 4
JUnit 5
• Leverages Java 8 lambdas and
functional interfaces
• Modularity, powerful
extensions mechanism
• No support for Runners and
Rules
• Spring tests based on
ThreadLocal usage break
TestNG
• Flexible grouping and running
of tests
• Different ordering to
assertion parameters than
JUnit
Spock
• Data tables with multi-line
strings
• No need for mocking
framework
• Getting used to Groovy-
based DSL
• Additional test source
directory
Other Java Test Frameworks
Type Highlights
Mockito Mock Interface injection, Data control, Verification
Spring Test Dependency Inject Spring config doc, Transaction rollback
Arquillian JEE Server Stub Embedded JEE server functionality
Cucumber BDD Gherkin-based communication with SME
Wiremock Service Virtual Lightweight service stubs
Spring Cloud
Contract
Consumer Driven Uses Wiremock under the hood
Hoverfly Service Virtual Full system service virtualization
ArchUnit Architecture Consistent -ilities w/o bureaucracy
–Ben Franklin
“The bitterness of poor quality remains long after
the sweetness of low price is forgotten.”
Test Source Layout
❖ Maven
❖ All in src/test/java or src/test/groovy
❖ Use surefire and failsafe include / exclude to control test execution (Unit = *Test, Integration = *IT)
❖ Define non-default profile for integration tests
❖ Use jacoco-maven-plugin to merge test coverage
❖ Gradle
❖ Utilize gradle-testsets-plugin and don’t link into default build
❖ Separate directories (Unit = src/test/java, Integration = src/integrationTest/java)
❖ Use Jacoco plugin to merge test coverage
❖ Sonar
❖ Automatically merges all test coverage in one metrics as of v6.x
–Aristotle
“Quality is not an act, it is a habit.”
What and How
When to Unit Test
- Questionable
- Code obvious at first glance
- Coordinating logic
✓ Absolutely Mandatory
✓ Algorithmic logic
✓ Complex code with many
dependencies
Vikas Hazrati on Knoldus blog
What to Test
Category Test Category Test
DTO
Serialization, equals,
hashCode
DAO/Repository
Integration tests against
actual datastore
Converters, Parsers,
Serializers, Validators
Source data from test data
parameters or files on class
path
Utility Methods Every branch, edge cases
Routers, Coordinators
Decision logic if any
extracted into methods
Business Rules
BDD specifications, All pairs
testing
JavaEE EJBs, JCAs Use Arquillian REST Controllers
Handling of optional
parameters, Use REST
framework-provided mocks
APIs
Integration tests verifying
wiring and configuration of
framework AOP
UIs Basic wiring, algorithms
Docker Images
Wiring, startup, health
check
Third-party Libraries
Integration of generated
code, Behavior assumptions
Data Transfer Object
public class ExampleEntityPKTest {
private final Logger logger = LoggerFactory.getLogger(ExampleEntityPKTest.class);
@Test
public void shouldSerializeAndDeserializeRetainingEquality() {
String employeeId = "99377";
String postingId = "DEC18";
ExampleEntityPK original = new ExampleEntityPK();
original.setPostingId(postingId);
original.setEmployeeId(employeeId);
ExampleEntityPK copy = (ExampleEntityPK)
SerializationUtils.deserialize(SerializationUtils.serialize(original));
assertEquals(original, copy);
assertEquals(original.hashCode(), copy.hashCode());
assertEquals(postingId, copy.getPostingId());
assertEquals(employeeId, copy.getEmployeeId());
}
@Test
public void shouldTreatObjectsWithDifferentValuesAsNotEqual() {
ExampleEntityPK pk1 = new ExampleEntityPK("99377", "JUL19TEST");
ExampleEntityPK pk2 = new ExampleEntityPK("11", "JUL19TEST");
assertEquals(pk1, pk1);
assertFalse(pk1.equals(pk2));
assertFalse(pk1.hashCode() == pk2.hashCode());
assertFalse(pk1.equals(null));
assertFalse(pk1.equals(pk1.getPostingId()));
}
@Test
public void shouldSortByPostingIdAndThenEmployeeId() {
ExampleEntityPK pk1 = new ExampleEntityPK("99377", "JUL19TEST");
ExampleEntityPK pk2 = new ExampleEntityPK(“11", "JUL19TEST");
assertTrue(pk1.compareTo(pk2) > 0);
}
}
Data Access Object
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = { DatabaseConfig.class })
@TestPropertySource("/test-application.properties")
public class EmployeeRepositoryITest {
@Autowired
private EmployeeRepository repository;
@Autowired
private DataSource dataSource;
@Test
public void shouldRetrievePageOfEmployees() {
PageRequest pageable = PageRequest.of(0, 32, Sort.Direction.ASC, "employeeId");
Page<Employee> results = repository.findAll(pageable);
assertFalse(results.getContent().isEmpty());
}
@Test
public void shouldRetrieveEmployeeByEmployeeId() {
PageRequest pageable = PageRequest.of(4, 4, Sort.Direction.ASC, "employeeId");
Page<Employee> results = repository.findAll(pageable);
assertFalse(results.getContent().isEmpty());
for (Employee em : results.getContent()) {
Optional<Employee> result = repository.findByEmployeeId(em.getEmployeeId());
assertTrue(result.isPresent());
}
}
@Test
public void shouldRetrieveValuesFromPersonnel() {
Optional<Employee> result = repository.findById(retrieveValidEmployeeId());
assertTrue(result.isPresent());
assertNotNull(result.get().getSeniorityDate());
}
private Long retrieveValidEmployeeId() {
Long result = null;
try (Connection conn = dataSource();
PreparedStatement ps = conn.prepareStatement("SELECT MAX(employee_id) FROM employee")) {
try (ResultSet rs = ps.executeQuery()) {
rs.next();
result = rs.getLong(1);
}
} catch (SQLException cause) {
throw new IllegalStateException(cause);
}
return result;
}
}
Converters
public class EmployeeConverterTest {
@Test
public void shouldConvertFullyPopulatedEntity() {
EmployeeConverter converter = new EmployeeConverter();
EmployeeEntity source = loadEmployeeEntity(“employee-fully-populated.json”);
Employee target = converter.convert(source);
assertEquals(source.getEmployeeId(), target.getEmployeeId());
assertEquals(source.getName(), target.getEmployeeName());
}
@Test
public void shouldConvertNullEntity() {
EmployeeConverter converter = new EmployeeConverter();
EmployeeEntity source = null;
Employee target = converter.convert(source);
assertNull(target);
}
private EmployeeEntity loadEmployeeEntity(String fileName) {
EmployeeEntity entity = null;
ObjectMapper objectMapper = new ObjectMapper();
try (InputStream stream = getClass().getResourceAsStream(fileName)) {
entity = objectMapper.readValue(stream, EmployeeEntity.class);
} catch (IOException cause) {
throw new IllegalStateException(cause);
}
return entity;
}
}
Utility Methods
public class IdentifierUtilsTest {
private final Logger logger = LoggerFactory.getLogger(IdentifierUtilsTest.class);
@Test
public void shouldExtractEmployeeIdFromValidIds() {
String[] pathIds = { "947334.APR19", "947334.APR%202019%20X", };
for (String pathId : pathIds) {
String employeeId = IdentifierUtils.extractEmployeeIdFromPathId(pathId);
logger.info("{}", employeeId);
assertTrue(StringUtils.hasText(employeeId));
}
}
@Test
public void shouldExtractPostingIdFromValidIds() {
String[] pathIds = { "947334.APR19", "947334.APR%202019%20X", "947334.APR19.x", };
for (String pathId : pathIds) {
String postingId = IdentifierUtils.extractPostingIdFromPathId(pathId);
logger.info("{}", postingId);
assertTrue(StringUtils.hasText(postingId));
}
}
@Test
public void shouldThrowExceptionForEmployeeIdFromInvalidIds() {
String[] pathIds = { "947334", "947334.", "947334-APR19.", };
for (String pathId : pathIds) {
try {
String employeeId = IdentifierUtils.extractEmployeeIdFromPathId(pathId);
assertTrue(StringUtils.hasText(employeeId));
fail("should have thrown exception");
} catch (IllegalArgumentException exception) {
logger.info("{}", exception.getMessage());
}
}
}
@Test
public void shouldThrowExceptionForPostingIdFromInvalidIds() {
String[] pathIds = { "947334", "947334.", "947334-APR19.", };
for (String pathId : pathIds) {
try {
String postingId = IdentifierUtils.extractPostingIdFromPathId(pathId);
assertTrue(StringUtils.hasText(postingId));
fail("should have thrown exception");
} catch (IllegalArgumentException exception) {
logger.info("{}", exception.getMessage());
}
}
}
}
Business Rules
public class RpnCalculatorStepdefs implements En {
private RpnCalculator calc;
public RpnCalculatorStepdefs() {
Given("a calculator I just turned on", () -> {
calc = new RpnCalculator();
});
When("I add {int} and {int}", (Integer arg1, Integer arg2) -> {
calc.push(arg1);
calc.push(arg2);
calc.push("+");
});
Given("I press (.+)", (String what) -> calc.push(what));
Then("the result is {double}", (Integer expected) -> assertEquals(expected, calc.value()));
Then("the result is {int}", (Integer expected) -> assertEquals(expected.doubleValue(), calc.value()));
Before(new String[]{"not @foo"}, (Scenario scenario) -> {
scenario.write("Runs before scenarios *not* tagged with @foo");
});
After((Scenario scenario) -> {
// result.write("HELLLLOO");
});
Given("the previous entries:", (DataTable dataTable) -> {
List<Entry> entries = dataTable.asList(Entry.class);
for (Entry entry : entries) {
calc.push(entry.first);
calc.push(entry.second);
calc.push(entry.operation);
}
});
}
static final class Entry {
private final Integer first;
private final Integer second;
private final String operation;
Entry(Integer first, Integer second, String operation) {
this.first = first;
this.second = second;
this.operation = operation;
}
}
}
All-Pairs Testing
❖ For each pair of input parameters, tests all possible
discrete combinations of those parameters
❖ The most common bugs in a program are generally
triggered by either a single input parameter or an
interaction between pairs of parameters
❖ Software available to generate optimum test data
EJB
@RunWith(Arquillian.class)
public class MemberRegistrationTest {
@Deployment
public static Archive<?> createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
.addClasses(Member.class, MemberRegistration.class, Resources.class)
.addAsResource("META-INF/test-persistence.xml", "META-INF/persistence.xml")
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
// Deploy our test datasource
.addAsWebInfResource("test-ds.xml", "test-ds.xml");
}
@Inject
MemberRegistration memberRegistration;
@Inject
Logger log;
@Test
public void testRegister() throws Exception {
Member newMember = new Member();
newMember.setName("Jane Doe");
newMember.setEmail("jane@mailinator.com");
newMember.setPhoneNumber("2125551234");
memberRegistration.register(newMember);
assertNotNull(newMember.getId());
log.info(newMember.getName() + " was persisted with id " + newMember.getId());
}
}
Concurrency
public class MicrometerTestApplicationTests {
private Logger logger = LoggerFactory.getLogger(MicrometerTestApplicationTests.class);
@Autowired
private WebTestClient webClient;
@Test
public void threadPoolResponseDistribution() throws BrokenBarrierException, InterruptedException {
int clients = 8;
int runs = 2048;
CyclicBarrier barrier = new CyclicBarrier(clients + 1);
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < clients; i++) {
executorService.submit(new ThreadPoolTestRunner(barrier, runs));
}
barrier.await();
barrier.await();
webClient.get().uri("/actuator/mappings").exchange().expectStatus().isOk();
webClient.get().uri("/actuator/prometheus").exchange().expectStatus().isOk();
FluxExchangeResult<String> stats = webClient.get().uri("/stats/tpool").exchange().returnResult(String.class);
logger.info("Thread Pool Test Result: {}", new String(stats.getResponseBodyContent()));
}
FluxExchangeResult<String> stats = webClient.get().uri("/stats/hystrix").exchange().returnResult(String.class);
logger.info("Hystrix Test Result: {}", new String(stats.getResponseBodyContent()));
}
class ThreadPoolTestRunner implements Runnable {
private CyclicBarrier barrier;
private int runs;
ThreadPoolTestRunner(CyclicBarrier barrier, int runs) {
this.barrier = barrier;
this.runs = runs;
}
@Override
public void run() {
try {
barrier.await();
for (int i = 0; i < runs; i++) {
webClient.get().uri("/tpool/{id}", UUID.randomUUID().toString()).exchange().expectStatus().isOk();
}
barrier.await();
} catch (InterruptedException | BrokenBarrierException ignore) {
fail("improperly configured test");
}
}
}
Testability Refactoring
–Andrew Hunt and Dave Thomas
“It’s not at all important to get it right the first
time. It’s vitally important to get it right the last
time.”
Testability Aphorisms
❖ Static getInstance involving a remote connection is EVIL
❖ PowerMock provides powerful functionality which should
NEVER be used
❖ PowerMock required == Redesign required
❖ God objects need the Single Responsibility Principle
applied
❖ In method section comments should be sub-method names
❖ Minimize leaky abstractions
–powermock.github.io
“Please note that PowerMock is mainly intended
for people with expert knowledge in unit testing.
Putting it in the hands of junior developers may
cause more harm than good.”
Test Automation Projects
–George Santayana
“Those who cannot remember the past are
condemned to repeat it.”
Test Automation Anti-Patterns
1. Mushrooming
• Stage 1: Small and Localized
• Stage 2: Generalization
• Stage 3: Staffing
• Stage 4: Development of Non-Core Features
• Stage 5: Overload
2. The Competition
• Variety 1: Different teams use different frameworks
• Variety 2: Different teams feed requirements to enterprise effort and one team gets favored
• Variety 3: Mushrooming at stage 5 so team starts new solution at stage 1
3. The Night Time Fallacy
• Test Automation Truism: Machines create work for more testers
• The Tragedy of the Commons: Five teams each assume 12 hours to test time: 5 teams * 12 hours = 60 hours
4. Going for the Numbers
• Point and click creation to up numbers but poorly engineered for resiliency
5. The Sorcerer’s Apprentice Syndrome
• Mimicking human actions sound straight forward, but is sometimes hard to accomplish programmatically and is frequently
inefficient.
The Pathologies of Failed Test Automation Projects - Michael Stahl, July 2013
Test Data Management
Test Data Strategies
❖ Use actual production data
❖ PII, PCI, HIPAA data must be masked
❖ Use queries to get valid test values
❖ Use automatic rollback for data changing tests
❖ Delete and refresh on a regular basis
❖ Generate fake data
❖ Domain specific generators
❖ Generate per test
❖ Import reference data
❖ Periodic cleanup
–Kaner, Bach, Pettichord
“Testers don’t like to break things; they like to
dispel the illusion that things work.”
Future of Enterprise QA
❖ Embedded in delivery team
❖ Gherkin specification development
❖ Exploratory testing
❖ Risk-based test prioritization
❖ Independent group
❖ AI-assisted intelligence
❖ Customer experience optimization and insights
❖ Robotic process automation
–Jerry Weinberg
“You can be a great tester if you have
programming skills. You can also be a great tester
if you have no programming skills at all. And, you
can be a lousy tester with or without programming
skills. A great tester will learn what skills she needs
to continue to be great, in her own style.”
Testing in Production Methodologies
❖ A/B Testing (aka Online Controlled Experimentation)
❖ Some percent of users of a website or service are unbeknownst to them given an alternate
experience (a new version of the service). Data is then collected on how users act in the old versus
new service, which can be analyzed to determine whether the new proposed change is good or not.
❖ Ramped Deployment
❖ Using Exposure Control, a new deployment of a website or service is gradually rolled out. First to a
small percentage of users, and then ultimately to all of them. At each stage the software is
monitored, and if any critical issues are uncovered that cannot be remedied, the deployment is
rolled back.
❖ Shadowing
❖ The system under test is deployed and uses real production data in real-time, but the results are not
exposed to the end user.
Source: https://blogs.msdn.microsoft.com/seliot/2011/06/07/testing-in-production-tip-it-really-happensexamples-from-facebook-amazon-google-and-microsoft/
–Isaac Asimov
“The most exciting phrase to hear in science, the
one that heralds discoveries, is not ‘Eureka!’ but
‘Now that’s funny…”
Questions?

More Related Content

What's hot

ETICS supporting compliance and interoperability, Gabriele Giammatteo, Engine...
ETICS supporting compliance and interoperability, Gabriele Giammatteo, Engine...ETICS supporting compliance and interoperability, Gabriele Giammatteo, Engine...
ETICS supporting compliance and interoperability, Gabriele Giammatteo, Engine...
OW2
 
Distributed tracing using open tracing &amp; jaeger 2
Distributed tracing using open tracing &amp; jaeger 2Distributed tracing using open tracing &amp; jaeger 2
Distributed tracing using open tracing &amp; jaeger 2
Chandresh Pancholi
 
Finding and exploiting novel flaws in Java software (SyScan 2015)
Finding and exploiting novel flaws in Java software (SyScan 2015)Finding and exploiting novel flaws in Java software (SyScan 2015)
Finding and exploiting novel flaws in Java software (SyScan 2015)
David Jorm
 
OpenDaylight Brisbane User Group - OpenDaylight Security
OpenDaylight Brisbane User Group - OpenDaylight SecurityOpenDaylight Brisbane User Group - OpenDaylight Security
OpenDaylight Brisbane User Group - OpenDaylight Security
David Jorm
 
SyScan 2016 - Remote code execution via Java native deserialization
SyScan 2016 - Remote code execution via Java native deserializationSyScan 2016 - Remote code execution via Java native deserialization
SyScan 2016 - Remote code execution via Java native deserialization
David Jorm
 
SDN NFV NV OpenNetwork @ VMUG.IT 20150529
SDN NFV NV OpenNetwork @ VMUG.IT 20150529SDN NFV NV OpenNetwork @ VMUG.IT 20150529
SDN NFV NV OpenNetwork @ VMUG.IT 20150529
VMUG IT
 
Secure your Java EE projects by using JOnAS Java EE server audit & diagnostic...
Secure your Java EE projects by using JOnAS Java EE server audit & diagnostic...Secure your Java EE projects by using JOnAS Java EE server audit & diagnostic...
Secure your Java EE projects by using JOnAS Java EE server audit & diagnostic...
Florent BENOIT
 
ElasTest Webinar
ElasTest WebinarElasTest Webinar
ElasTest Webinar
ElasTest Project
 
Java concurrency in practice
Java concurrency in practiceJava concurrency in practice
Java concurrency in practice
Mikalai Alimenkou
 
Windows 10 - Endpoint Security Improvements and the Implant Since Windows 2000
Windows 10 - Endpoint Security Improvements and the Implant Since Windows 2000Windows 10 - Endpoint Security Improvements and the Implant Since Windows 2000
Windows 10 - Endpoint Security Improvements and the Implant Since Windows 2000
CTruncer
 
The State of the Veil Framework
The State of the Veil FrameworkThe State of the Veil Framework
The State of the Veil Framework
VeilFramework
 
Pentester++
Pentester++Pentester++
Pentester++
CTruncer
 
AntiVirus Evasion Reconstructed - Veil 3.0
AntiVirus Evasion Reconstructed - Veil 3.0AntiVirus Evasion Reconstructed - Veil 3.0
AntiVirus Evasion Reconstructed - Veil 3.0
CTruncer
 
An EyeWitness View into your Network
An EyeWitness View into your NetworkAn EyeWitness View into your Network
An EyeWitness View into your Network
CTruncer
 
Monitoring Cloud Native Applications with Prometheus
Monitoring Cloud Native Applications with PrometheusMonitoring Cloud Native Applications with Prometheus
Monitoring Cloud Native Applications with Prometheus
Jacopo Nardiello
 
Bgoug 2019.11 building free, open-source, plsql products in cloud
Bgoug 2019.11   building free, open-source, plsql products in cloudBgoug 2019.11   building free, open-source, plsql products in cloud
Bgoug 2019.11 building free, open-source, plsql products in cloud
Jacek Gebal
 
Cpp Testing Techniques Tips and Tricks - Cpp Europe
Cpp Testing Techniques Tips and Tricks - Cpp EuropeCpp Testing Techniques Tips and Tricks - Cpp Europe
Cpp Testing Techniques Tips and Tricks - Cpp Europe
Clare Macrae
 
HAProxy as Egress Controller
HAProxy as Egress ControllerHAProxy as Egress Controller
HAProxy as Egress Controller
Julien Pivotto
 
AusCERT 2016: CVE and alternatives
AusCERT 2016: CVE and alternativesAusCERT 2016: CVE and alternatives
AusCERT 2016: CVE and alternatives
David Jorm
 
POUG Meetup 1st MArch 2019 - utPLSQL v3 - Testing Framework for PL/SQL
POUG Meetup 1st MArch 2019 - utPLSQL v3 - Testing Framework for PL/SQLPOUG Meetup 1st MArch 2019 - utPLSQL v3 - Testing Framework for PL/SQL
POUG Meetup 1st MArch 2019 - utPLSQL v3 - Testing Framework for PL/SQL
Jacek Gebal
 

What's hot (20)

ETICS supporting compliance and interoperability, Gabriele Giammatteo, Engine...
ETICS supporting compliance and interoperability, Gabriele Giammatteo, Engine...ETICS supporting compliance and interoperability, Gabriele Giammatteo, Engine...
ETICS supporting compliance and interoperability, Gabriele Giammatteo, Engine...
 
Distributed tracing using open tracing &amp; jaeger 2
Distributed tracing using open tracing &amp; jaeger 2Distributed tracing using open tracing &amp; jaeger 2
Distributed tracing using open tracing &amp; jaeger 2
 
Finding and exploiting novel flaws in Java software (SyScan 2015)
Finding and exploiting novel flaws in Java software (SyScan 2015)Finding and exploiting novel flaws in Java software (SyScan 2015)
Finding and exploiting novel flaws in Java software (SyScan 2015)
 
OpenDaylight Brisbane User Group - OpenDaylight Security
OpenDaylight Brisbane User Group - OpenDaylight SecurityOpenDaylight Brisbane User Group - OpenDaylight Security
OpenDaylight Brisbane User Group - OpenDaylight Security
 
SyScan 2016 - Remote code execution via Java native deserialization
SyScan 2016 - Remote code execution via Java native deserializationSyScan 2016 - Remote code execution via Java native deserialization
SyScan 2016 - Remote code execution via Java native deserialization
 
SDN NFV NV OpenNetwork @ VMUG.IT 20150529
SDN NFV NV OpenNetwork @ VMUG.IT 20150529SDN NFV NV OpenNetwork @ VMUG.IT 20150529
SDN NFV NV OpenNetwork @ VMUG.IT 20150529
 
Secure your Java EE projects by using JOnAS Java EE server audit & diagnostic...
Secure your Java EE projects by using JOnAS Java EE server audit & diagnostic...Secure your Java EE projects by using JOnAS Java EE server audit & diagnostic...
Secure your Java EE projects by using JOnAS Java EE server audit & diagnostic...
 
ElasTest Webinar
ElasTest WebinarElasTest Webinar
ElasTest Webinar
 
Java concurrency in practice
Java concurrency in practiceJava concurrency in practice
Java concurrency in practice
 
Windows 10 - Endpoint Security Improvements and the Implant Since Windows 2000
Windows 10 - Endpoint Security Improvements and the Implant Since Windows 2000Windows 10 - Endpoint Security Improvements and the Implant Since Windows 2000
Windows 10 - Endpoint Security Improvements and the Implant Since Windows 2000
 
The State of the Veil Framework
The State of the Veil FrameworkThe State of the Veil Framework
The State of the Veil Framework
 
Pentester++
Pentester++Pentester++
Pentester++
 
AntiVirus Evasion Reconstructed - Veil 3.0
AntiVirus Evasion Reconstructed - Veil 3.0AntiVirus Evasion Reconstructed - Veil 3.0
AntiVirus Evasion Reconstructed - Veil 3.0
 
An EyeWitness View into your Network
An EyeWitness View into your NetworkAn EyeWitness View into your Network
An EyeWitness View into your Network
 
Monitoring Cloud Native Applications with Prometheus
Monitoring Cloud Native Applications with PrometheusMonitoring Cloud Native Applications with Prometheus
Monitoring Cloud Native Applications with Prometheus
 
Bgoug 2019.11 building free, open-source, plsql products in cloud
Bgoug 2019.11   building free, open-source, plsql products in cloudBgoug 2019.11   building free, open-source, plsql products in cloud
Bgoug 2019.11 building free, open-source, plsql products in cloud
 
Cpp Testing Techniques Tips and Tricks - Cpp Europe
Cpp Testing Techniques Tips and Tricks - Cpp EuropeCpp Testing Techniques Tips and Tricks - Cpp Europe
Cpp Testing Techniques Tips and Tricks - Cpp Europe
 
HAProxy as Egress Controller
HAProxy as Egress ControllerHAProxy as Egress Controller
HAProxy as Egress Controller
 
AusCERT 2016: CVE and alternatives
AusCERT 2016: CVE and alternativesAusCERT 2016: CVE and alternatives
AusCERT 2016: CVE and alternatives
 
POUG Meetup 1st MArch 2019 - utPLSQL v3 - Testing Framework for PL/SQL
POUG Meetup 1st MArch 2019 - utPLSQL v3 - Testing Framework for PL/SQLPOUG Meetup 1st MArch 2019 - utPLSQL v3 - Testing Framework for PL/SQL
POUG Meetup 1st MArch 2019 - utPLSQL v3 - Testing Framework for PL/SQL
 

Similar to Deliver Faster with BDD/TDD - Designing Automated Tests That Don't Suck

How to Build Your Own Test Automation Framework?
How to Build Your Own Test Automation Framework?How to Build Your Own Test Automation Framework?
How to Build Your Own Test Automation Framework?
Dmitry Buzdin
 
Into The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applicationsInto The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applications
Ortus Solutions, Corp
 
Testing 101
Testing 101Testing 101
Testing 101
Noam Barkai
 
Performance Test Driven Development with Oracle Coherence
Performance Test Driven Development with Oracle CoherencePerformance Test Driven Development with Oracle Coherence
Performance Test Driven Development with Oracle Coherence
aragozin
 
Test it! Unit, mocking and in-container Meet Arquillian!
Test it! Unit, mocking and in-container Meet Arquillian!Test it! Unit, mocking and in-container Meet Arquillian!
Test it! Unit, mocking and in-container Meet Arquillian!
Ivan Ivanov
 
Building functional Quality Gates with ReportPortal
Building functional Quality Gates with ReportPortalBuilding functional Quality Gates with ReportPortal
Building functional Quality Gates with ReportPortal
Dmitriy Gumeniuk
 
Testing w-mocks
Testing w-mocksTesting w-mocks
Testing w-mocks
Macon Pegram
 
Cerberus : Framework for Manual and Automated Testing (Web Application)
Cerberus : Framework for Manual and Automated Testing (Web Application)Cerberus : Framework for Manual and Automated Testing (Web Application)
Cerberus : Framework for Manual and Automated Testing (Web Application)
CIVEL Benoit
 
Cerberus_Presentation1
Cerberus_Presentation1Cerberus_Presentation1
Cerberus_Presentation1
CIVEL Benoit
 
Google, quality and you
Google, quality and youGoogle, quality and you
Google, quality and you
nelinger
 
DevOps - Boldly Go for Distro
DevOps - Boldly Go for DistroDevOps - Boldly Go for Distro
DevOps - Boldly Go for Distro
Paul Boos
 
Agile Engineering Best Practices by Richard Cheng
Agile Engineering Best Practices by Richard ChengAgile Engineering Best Practices by Richard Cheng
Agile Engineering Best Practices by Richard Cheng
Excella
 
Embracing Disruption: Adding a Bit of Chaos to Help You Grow
Embracing Disruption: Adding a Bit of Chaos to Help You GrowEmbracing Disruption: Adding a Bit of Chaos to Help You Grow
Embracing Disruption: Adding a Bit of Chaos to Help You Grow
Paul Balogh
 
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
NaviAningi
 
KKSD_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
KKSD_Testbirds_Selenium_eclipsecon_FINAL_0.pptKKSD_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
KKSD_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
Kiran Kumar SD
 
How to become a testing expert
How to become a testing expertHow to become a testing expert
How to become a testing expert
gaoliang641
 
Software Quality and Test Strategies for Ruby and Rails Applications
Software Quality and Test Strategies for Ruby and Rails ApplicationsSoftware Quality and Test Strategies for Ruby and Rails Applications
Software Quality and Test Strategies for Ruby and Rails Applications
Bhavin Javia
 
Test Dependencies and the Future of Build Acceleration
Test Dependencies and the Future of Build AccelerationTest Dependencies and the Future of Build Acceleration
Test Dependencies and the Future of Build Acceleration
New York City College of Technology Computer Systems Technology Colloquium
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
Sergey Aganezov
 
Anatomy of a Build Pipeline
Anatomy of a Build PipelineAnatomy of a Build Pipeline
Anatomy of a Build Pipeline
Samuel Brown
 

Similar to Deliver Faster with BDD/TDD - Designing Automated Tests That Don't Suck (20)

How to Build Your Own Test Automation Framework?
How to Build Your Own Test Automation Framework?How to Build Your Own Test Automation Framework?
How to Build Your Own Test Automation Framework?
 
Into The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applicationsInto The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applications
 
Testing 101
Testing 101Testing 101
Testing 101
 
Performance Test Driven Development with Oracle Coherence
Performance Test Driven Development with Oracle CoherencePerformance Test Driven Development with Oracle Coherence
Performance Test Driven Development with Oracle Coherence
 
Test it! Unit, mocking and in-container Meet Arquillian!
Test it! Unit, mocking and in-container Meet Arquillian!Test it! Unit, mocking and in-container Meet Arquillian!
Test it! Unit, mocking and in-container Meet Arquillian!
 
Building functional Quality Gates with ReportPortal
Building functional Quality Gates with ReportPortalBuilding functional Quality Gates with ReportPortal
Building functional Quality Gates with ReportPortal
 
Testing w-mocks
Testing w-mocksTesting w-mocks
Testing w-mocks
 
Cerberus : Framework for Manual and Automated Testing (Web Application)
Cerberus : Framework for Manual and Automated Testing (Web Application)Cerberus : Framework for Manual and Automated Testing (Web Application)
Cerberus : Framework for Manual and Automated Testing (Web Application)
 
Cerberus_Presentation1
Cerberus_Presentation1Cerberus_Presentation1
Cerberus_Presentation1
 
Google, quality and you
Google, quality and youGoogle, quality and you
Google, quality and you
 
DevOps - Boldly Go for Distro
DevOps - Boldly Go for DistroDevOps - Boldly Go for Distro
DevOps - Boldly Go for Distro
 
Agile Engineering Best Practices by Richard Cheng
Agile Engineering Best Practices by Richard ChengAgile Engineering Best Practices by Richard Cheng
Agile Engineering Best Practices by Richard Cheng
 
Embracing Disruption: Adding a Bit of Chaos to Help You Grow
Embracing Disruption: Adding a Bit of Chaos to Help You GrowEmbracing Disruption: Adding a Bit of Chaos to Help You Grow
Embracing Disruption: Adding a Bit of Chaos to Help You Grow
 
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
190711_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
 
KKSD_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
KKSD_Testbirds_Selenium_eclipsecon_FINAL_0.pptKKSD_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
KKSD_Testbirds_Selenium_eclipsecon_FINAL_0.ppt
 
How to become a testing expert
How to become a testing expertHow to become a testing expert
How to become a testing expert
 
Software Quality and Test Strategies for Ruby and Rails Applications
Software Quality and Test Strategies for Ruby and Rails ApplicationsSoftware Quality and Test Strategies for Ruby and Rails Applications
Software Quality and Test Strategies for Ruby and Rails Applications
 
Test Dependencies and the Future of Build Acceleration
Test Dependencies and the Future of Build AccelerationTest Dependencies and the Future of Build Acceleration
Test Dependencies and the Future of Build Acceleration
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
Anatomy of a Build Pipeline
Anatomy of a Build PipelineAnatomy of a Build Pipeline
Anatomy of a Build Pipeline
 

Recently uploaded

UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
Peter Muessig
 
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdfAutomated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
timtebeek1
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptxLORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
lorraineandreiamcidl
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Crescat
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
Aftab Hussain
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
Shane Coughlan
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
Remote DBA Services
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
Octavian Nadolu
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
Łukasz Chruściel
 
What is Augmented Reality Image Tracking
What is Augmented Reality Image TrackingWhat is Augmented Reality Image Tracking
What is Augmented Reality Image Tracking
pavan998932
 
What is Master Data Management by PiLog Group
What is Master Data Management by PiLog GroupWhat is Master Data Management by PiLog Group
What is Master Data Management by PiLog Group
aymanquadri279
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
SOCRadar
 
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
kalichargn70th171
 
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
mz5nrf0n
 
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Julian Hyde
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Łukasz Chruściel
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
Green Software Development
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
Green Software Development
 
E-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet DynamicsE-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet Dynamics
Hornet Dynamics
 

Recently uploaded (20)

UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
 
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdfAutomated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptxLORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
 
What is Augmented Reality Image Tracking
What is Augmented Reality Image TrackingWhat is Augmented Reality Image Tracking
What is Augmented Reality Image Tracking
 
What is Master Data Management by PiLog Group
What is Master Data Management by PiLog GroupWhat is Master Data Management by PiLog Group
What is Master Data Management by PiLog Group
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
 
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
 
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
 
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
 
E-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet DynamicsE-commerce Development Services- Hornet Dynamics
E-commerce Development Services- Hornet Dynamics
 

Deliver Faster with BDD/TDD - Designing Automated Tests That Don't Suck

  • 1. Kevin Brockhoff Deliver Faster with BDD/TDD Designing Automated Tests That Don’t Suck
  • 2. –Uncle Bob “The only way to go fast is to go well.”
  • 3. Accelerate ❖ Software Delivery Performance Metrics That Matter ❖ Deployment Frequency ❖ Lead Time for Changes ❖ Mean Time To Restore (MTTR) ❖ Change Failure Rate Accelerate: The Science of Lean Software and DevOps: Building and Scaling High Performing Technology Organizations By Nicole Forsgren PhD, Jez Humble, and Gene Kim
  • 4. Fast vs Quality Annual State of DevOps Report sponsored by Puppet Labs
  • 5. –Jerry Weinberg “A system is never finished being developed until it ceases to be used.”
  • 6. –John Woods “Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.”
  • 8. –Michael Feathers “Legacy code is code without tests.”
  • 9. Deliver Valuable Software Faster Problem How TDD/BDD Can Help Long QA Test Cycles Identify incorrect behavior before release to QA Rework Identify incorrect behavior during initial development so can fix when most familiar with the code Disproportionate time spent studying code before making small change Confidence tests will identify if change will break other behavior Slow and difficult client development Verify API usability and tests as documentation Slow and difficult to extend and/or add features Testability strongly correlated with flexibility and extensibility
  • 10. –Chinese proverb “To be uncertain is to be uncomfortable, but to be certain is to be ridiculous.”
  • 11. Testing Pyramid Testing pyramid concept introduced in Succeeding with Agile by Mike Cohn
  • 12. End-to-End Tests ❖ Developers like it because it offloads most, if not all, of the testing to others. ❖ Managers and decision-makers like it because tests that simulate real user scenarios can help them easily determine how a failing test would impact the user. ❖ Testers like it because they often worry about missing a bug or writing a test that does not verify real-world behavior; writing tests from the user's perspective often avoids both problems and gives the tester a greater sense of accomplishment. Days Left Pass % Notes 1 5% Everything is broken! Signing in to the service is broken. Almost all tests sign in a user, so almost all tests failed. 0 4% A partner team we rely on deployed a bad build to their testing environment yesterday. -1 54% A dev broke the save scenario yesterday (or the day before?). Half the tests save a document at some point in time. Devs spent most of the day determining if it's a frontend bug or a backend -2 54% It's a frontend bug, devs spent half of today figuring out where. -3 54% A bad fix was checked in yesterday. The mistake was pretty easy to spot, though, and a correct fix was checked in today. -4 1% Hardware failures occurred in the lab for our testing environment. -5 84% Many small bugs hiding behind the big bugs (e.g., sign-in broken, save broken). Still working on the small bugs. -6 87% We should be above 90%, but are not for some reason. -7 89.54% (Rounds up to 90%, close enough.) No fixes were checked in yesterday, so the tests must have been flaky yesterday. In Theory In Practice Source: Mike Wacker on Google Testing Blog
  • 14. –Fred Brooks “The hardest part of building a software system is deciding precisely what to build... No other part of the work so cripples the resulting system if done wrong. No other part is more difficult to rectify later”
  • 15. Java Unit Test Frameworks Strong Points Migrating from JUnit 4 JUnit 5 • Leverages Java 8 lambdas and functional interfaces • Modularity, powerful extensions mechanism • No support for Runners and Rules • Spring tests based on ThreadLocal usage break TestNG • Flexible grouping and running of tests • Different ordering to assertion parameters than JUnit Spock • Data tables with multi-line strings • No need for mocking framework • Getting used to Groovy- based DSL • Additional test source directory
  • 16. Other Java Test Frameworks Type Highlights Mockito Mock Interface injection, Data control, Verification Spring Test Dependency Inject Spring config doc, Transaction rollback Arquillian JEE Server Stub Embedded JEE server functionality Cucumber BDD Gherkin-based communication with SME Wiremock Service Virtual Lightweight service stubs Spring Cloud Contract Consumer Driven Uses Wiremock under the hood Hoverfly Service Virtual Full system service virtualization ArchUnit Architecture Consistent -ilities w/o bureaucracy
  • 17. –Ben Franklin “The bitterness of poor quality remains long after the sweetness of low price is forgotten.”
  • 18. Test Source Layout ❖ Maven ❖ All in src/test/java or src/test/groovy ❖ Use surefire and failsafe include / exclude to control test execution (Unit = *Test, Integration = *IT) ❖ Define non-default profile for integration tests ❖ Use jacoco-maven-plugin to merge test coverage ❖ Gradle ❖ Utilize gradle-testsets-plugin and don’t link into default build ❖ Separate directories (Unit = src/test/java, Integration = src/integrationTest/java) ❖ Use Jacoco plugin to merge test coverage ❖ Sonar ❖ Automatically merges all test coverage in one metrics as of v6.x
  • 19. –Aristotle “Quality is not an act, it is a habit.”
  • 21. When to Unit Test - Questionable - Code obvious at first glance - Coordinating logic ✓ Absolutely Mandatory ✓ Algorithmic logic ✓ Complex code with many dependencies Vikas Hazrati on Knoldus blog
  • 22. What to Test Category Test Category Test DTO Serialization, equals, hashCode DAO/Repository Integration tests against actual datastore Converters, Parsers, Serializers, Validators Source data from test data parameters or files on class path Utility Methods Every branch, edge cases Routers, Coordinators Decision logic if any extracted into methods Business Rules BDD specifications, All pairs testing JavaEE EJBs, JCAs Use Arquillian REST Controllers Handling of optional parameters, Use REST framework-provided mocks APIs Integration tests verifying wiring and configuration of framework AOP UIs Basic wiring, algorithms Docker Images Wiring, startup, health check Third-party Libraries Integration of generated code, Behavior assumptions
  • 23. Data Transfer Object public class ExampleEntityPKTest { private final Logger logger = LoggerFactory.getLogger(ExampleEntityPKTest.class); @Test public void shouldSerializeAndDeserializeRetainingEquality() { String employeeId = "99377"; String postingId = "DEC18"; ExampleEntityPK original = new ExampleEntityPK(); original.setPostingId(postingId); original.setEmployeeId(employeeId); ExampleEntityPK copy = (ExampleEntityPK) SerializationUtils.deserialize(SerializationUtils.serialize(original)); assertEquals(original, copy); assertEquals(original.hashCode(), copy.hashCode()); assertEquals(postingId, copy.getPostingId()); assertEquals(employeeId, copy.getEmployeeId()); } @Test public void shouldTreatObjectsWithDifferentValuesAsNotEqual() { ExampleEntityPK pk1 = new ExampleEntityPK("99377", "JUL19TEST"); ExampleEntityPK pk2 = new ExampleEntityPK("11", "JUL19TEST"); assertEquals(pk1, pk1); assertFalse(pk1.equals(pk2)); assertFalse(pk1.hashCode() == pk2.hashCode()); assertFalse(pk1.equals(null)); assertFalse(pk1.equals(pk1.getPostingId())); } @Test public void shouldSortByPostingIdAndThenEmployeeId() { ExampleEntityPK pk1 = new ExampleEntityPK("99377", "JUL19TEST"); ExampleEntityPK pk2 = new ExampleEntityPK(“11", "JUL19TEST"); assertTrue(pk1.compareTo(pk2) > 0); } }
  • 24. Data Access Object @RunWith(SpringRunner.class) @ContextConfiguration(classes = { DatabaseConfig.class }) @TestPropertySource("/test-application.properties") public class EmployeeRepositoryITest { @Autowired private EmployeeRepository repository; @Autowired private DataSource dataSource; @Test public void shouldRetrievePageOfEmployees() { PageRequest pageable = PageRequest.of(0, 32, Sort.Direction.ASC, "employeeId"); Page<Employee> results = repository.findAll(pageable); assertFalse(results.getContent().isEmpty()); } @Test public void shouldRetrieveEmployeeByEmployeeId() { PageRequest pageable = PageRequest.of(4, 4, Sort.Direction.ASC, "employeeId"); Page<Employee> results = repository.findAll(pageable); assertFalse(results.getContent().isEmpty()); for (Employee em : results.getContent()) { Optional<Employee> result = repository.findByEmployeeId(em.getEmployeeId()); assertTrue(result.isPresent()); } } @Test public void shouldRetrieveValuesFromPersonnel() { Optional<Employee> result = repository.findById(retrieveValidEmployeeId()); assertTrue(result.isPresent()); assertNotNull(result.get().getSeniorityDate()); } private Long retrieveValidEmployeeId() { Long result = null; try (Connection conn = dataSource(); PreparedStatement ps = conn.prepareStatement("SELECT MAX(employee_id) FROM employee")) { try (ResultSet rs = ps.executeQuery()) { rs.next(); result = rs.getLong(1); } } catch (SQLException cause) { throw new IllegalStateException(cause); } return result; } }
  • 25. Converters public class EmployeeConverterTest { @Test public void shouldConvertFullyPopulatedEntity() { EmployeeConverter converter = new EmployeeConverter(); EmployeeEntity source = loadEmployeeEntity(“employee-fully-populated.json”); Employee target = converter.convert(source); assertEquals(source.getEmployeeId(), target.getEmployeeId()); assertEquals(source.getName(), target.getEmployeeName()); } @Test public void shouldConvertNullEntity() { EmployeeConverter converter = new EmployeeConverter(); EmployeeEntity source = null; Employee target = converter.convert(source); assertNull(target); } private EmployeeEntity loadEmployeeEntity(String fileName) { EmployeeEntity entity = null; ObjectMapper objectMapper = new ObjectMapper(); try (InputStream stream = getClass().getResourceAsStream(fileName)) { entity = objectMapper.readValue(stream, EmployeeEntity.class); } catch (IOException cause) { throw new IllegalStateException(cause); } return entity; } }
  • 26. Utility Methods public class IdentifierUtilsTest { private final Logger logger = LoggerFactory.getLogger(IdentifierUtilsTest.class); @Test public void shouldExtractEmployeeIdFromValidIds() { String[] pathIds = { "947334.APR19", "947334.APR%202019%20X", }; for (String pathId : pathIds) { String employeeId = IdentifierUtils.extractEmployeeIdFromPathId(pathId); logger.info("{}", employeeId); assertTrue(StringUtils.hasText(employeeId)); } } @Test public void shouldExtractPostingIdFromValidIds() { String[] pathIds = { "947334.APR19", "947334.APR%202019%20X", "947334.APR19.x", }; for (String pathId : pathIds) { String postingId = IdentifierUtils.extractPostingIdFromPathId(pathId); logger.info("{}", postingId); assertTrue(StringUtils.hasText(postingId)); } } @Test public void shouldThrowExceptionForEmployeeIdFromInvalidIds() { String[] pathIds = { "947334", "947334.", "947334-APR19.", }; for (String pathId : pathIds) { try { String employeeId = IdentifierUtils.extractEmployeeIdFromPathId(pathId); assertTrue(StringUtils.hasText(employeeId)); fail("should have thrown exception"); } catch (IllegalArgumentException exception) { logger.info("{}", exception.getMessage()); } } } @Test public void shouldThrowExceptionForPostingIdFromInvalidIds() { String[] pathIds = { "947334", "947334.", "947334-APR19.", }; for (String pathId : pathIds) { try { String postingId = IdentifierUtils.extractPostingIdFromPathId(pathId); assertTrue(StringUtils.hasText(postingId)); fail("should have thrown exception"); } catch (IllegalArgumentException exception) { logger.info("{}", exception.getMessage()); } } } }
  • 27. Business Rules public class RpnCalculatorStepdefs implements En { private RpnCalculator calc; public RpnCalculatorStepdefs() { Given("a calculator I just turned on", () -> { calc = new RpnCalculator(); }); When("I add {int} and {int}", (Integer arg1, Integer arg2) -> { calc.push(arg1); calc.push(arg2); calc.push("+"); }); Given("I press (.+)", (String what) -> calc.push(what)); Then("the result is {double}", (Integer expected) -> assertEquals(expected, calc.value())); Then("the result is {int}", (Integer expected) -> assertEquals(expected.doubleValue(), calc.value())); Before(new String[]{"not @foo"}, (Scenario scenario) -> { scenario.write("Runs before scenarios *not* tagged with @foo"); }); After((Scenario scenario) -> { // result.write("HELLLLOO"); }); Given("the previous entries:", (DataTable dataTable) -> { List<Entry> entries = dataTable.asList(Entry.class); for (Entry entry : entries) { calc.push(entry.first); calc.push(entry.second); calc.push(entry.operation); } }); } static final class Entry { private final Integer first; private final Integer second; private final String operation; Entry(Integer first, Integer second, String operation) { this.first = first; this.second = second; this.operation = operation; } } }
  • 28. All-Pairs Testing ❖ For each pair of input parameters, tests all possible discrete combinations of those parameters ❖ The most common bugs in a program are generally triggered by either a single input parameter or an interaction between pairs of parameters ❖ Software available to generate optimum test data
  • 29. EJB @RunWith(Arquillian.class) public class MemberRegistrationTest { @Deployment public static Archive<?> createTestArchive() { return ShrinkWrap.create(WebArchive.class, "test.war") .addClasses(Member.class, MemberRegistration.class, Resources.class) .addAsResource("META-INF/test-persistence.xml", "META-INF/persistence.xml") .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") // Deploy our test datasource .addAsWebInfResource("test-ds.xml", "test-ds.xml"); } @Inject MemberRegistration memberRegistration; @Inject Logger log; @Test public void testRegister() throws Exception { Member newMember = new Member(); newMember.setName("Jane Doe"); newMember.setEmail("jane@mailinator.com"); newMember.setPhoneNumber("2125551234"); memberRegistration.register(newMember); assertNotNull(newMember.getId()); log.info(newMember.getName() + " was persisted with id " + newMember.getId()); } }
  • 30. Concurrency public class MicrometerTestApplicationTests { private Logger logger = LoggerFactory.getLogger(MicrometerTestApplicationTests.class); @Autowired private WebTestClient webClient; @Test public void threadPoolResponseDistribution() throws BrokenBarrierException, InterruptedException { int clients = 8; int runs = 2048; CyclicBarrier barrier = new CyclicBarrier(clients + 1); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < clients; i++) { executorService.submit(new ThreadPoolTestRunner(barrier, runs)); } barrier.await(); barrier.await(); webClient.get().uri("/actuator/mappings").exchange().expectStatus().isOk(); webClient.get().uri("/actuator/prometheus").exchange().expectStatus().isOk(); FluxExchangeResult<String> stats = webClient.get().uri("/stats/tpool").exchange().returnResult(String.class); logger.info("Thread Pool Test Result: {}", new String(stats.getResponseBodyContent())); } FluxExchangeResult<String> stats = webClient.get().uri("/stats/hystrix").exchange().returnResult(String.class); logger.info("Hystrix Test Result: {}", new String(stats.getResponseBodyContent())); } class ThreadPoolTestRunner implements Runnable { private CyclicBarrier barrier; private int runs; ThreadPoolTestRunner(CyclicBarrier barrier, int runs) { this.barrier = barrier; this.runs = runs; } @Override public void run() { try { barrier.await(); for (int i = 0; i < runs; i++) { webClient.get().uri("/tpool/{id}", UUID.randomUUID().toString()).exchange().expectStatus().isOk(); } barrier.await(); } catch (InterruptedException | BrokenBarrierException ignore) { fail("improperly configured test"); } } }
  • 32. –Andrew Hunt and Dave Thomas “It’s not at all important to get it right the first time. It’s vitally important to get it right the last time.”
  • 33. Testability Aphorisms ❖ Static getInstance involving a remote connection is EVIL ❖ PowerMock provides powerful functionality which should NEVER be used ❖ PowerMock required == Redesign required ❖ God objects need the Single Responsibility Principle applied ❖ In method section comments should be sub-method names ❖ Minimize leaky abstractions
  • 34. –powermock.github.io “Please note that PowerMock is mainly intended for people with expert knowledge in unit testing. Putting it in the hands of junior developers may cause more harm than good.”
  • 36. –George Santayana “Those who cannot remember the past are condemned to repeat it.”
  • 37. Test Automation Anti-Patterns 1. Mushrooming • Stage 1: Small and Localized • Stage 2: Generalization • Stage 3: Staffing • Stage 4: Development of Non-Core Features • Stage 5: Overload 2. The Competition • Variety 1: Different teams use different frameworks • Variety 2: Different teams feed requirements to enterprise effort and one team gets favored • Variety 3: Mushrooming at stage 5 so team starts new solution at stage 1 3. The Night Time Fallacy • Test Automation Truism: Machines create work for more testers • The Tragedy of the Commons: Five teams each assume 12 hours to test time: 5 teams * 12 hours = 60 hours 4. Going for the Numbers • Point and click creation to up numbers but poorly engineered for resiliency 5. The Sorcerer’s Apprentice Syndrome • Mimicking human actions sound straight forward, but is sometimes hard to accomplish programmatically and is frequently inefficient. The Pathologies of Failed Test Automation Projects - Michael Stahl, July 2013
  • 39. Test Data Strategies ❖ Use actual production data ❖ PII, PCI, HIPAA data must be masked ❖ Use queries to get valid test values ❖ Use automatic rollback for data changing tests ❖ Delete and refresh on a regular basis ❖ Generate fake data ❖ Domain specific generators ❖ Generate per test ❖ Import reference data ❖ Periodic cleanup
  • 40. –Kaner, Bach, Pettichord “Testers don’t like to break things; they like to dispel the illusion that things work.”
  • 41. Future of Enterprise QA ❖ Embedded in delivery team ❖ Gherkin specification development ❖ Exploratory testing ❖ Risk-based test prioritization ❖ Independent group ❖ AI-assisted intelligence ❖ Customer experience optimization and insights ❖ Robotic process automation
  • 42. –Jerry Weinberg “You can be a great tester if you have programming skills. You can also be a great tester if you have no programming skills at all. And, you can be a lousy tester with or without programming skills. A great tester will learn what skills she needs to continue to be great, in her own style.”
  • 43. Testing in Production Methodologies ❖ A/B Testing (aka Online Controlled Experimentation) ❖ Some percent of users of a website or service are unbeknownst to them given an alternate experience (a new version of the service). Data is then collected on how users act in the old versus new service, which can be analyzed to determine whether the new proposed change is good or not. ❖ Ramped Deployment ❖ Using Exposure Control, a new deployment of a website or service is gradually rolled out. First to a small percentage of users, and then ultimately to all of them. At each stage the software is monitored, and if any critical issues are uncovered that cannot be remedied, the deployment is rolled back. ❖ Shadowing ❖ The system under test is deployed and uses real production data in real-time, but the results are not exposed to the end user. Source: https://blogs.msdn.microsoft.com/seliot/2011/06/07/testing-in-production-tip-it-really-happensexamples-from-facebook-amazon-google-and-microsoft/
  • 44. –Isaac Asimov “The most exciting phrase to hear in science, the one that heralds discoveries, is not ‘Eureka!’ but ‘Now that’s funny…”