SlideShare a Scribd company logo
RSpock: Data-Driven Testing
Jean-Philippe Duchesne
• 80% reading code
• 20% writing code
• Some even say closer to 10:1
Read / Write Code
“I Have a Dream”
class MyThing
# ...
def do_something(a, b)
# Implementation details...
end
end
“I Have a Dream”
class MyThing
extend(T::Sig)
sig { params(a: Integer, b: Integer).returns(String) }
def do_something(a, b)
# Implementation details...
end
end
“I Have a Dream”
class MyThing
extend(T::Sig)
# Documentation
sig { params(a: Integer, b: Integer).returns(String) }
def do_something(a, b)
# Implementation details...
end
end
class MyThing
def do_something(a, b)
#...
end
end
Mental Model
class MyThing
def do_something(a, b)
#...
end
end
Tests as Specification
class MyThingTest < HermeticTestCase
test "#do_something with arg1 and arg2 does X" do
# ...
end
test "#foo does something amazing" do
# ...
end
test "#do_something does Y if param1 is nil" do
# ...
end
test "#bar does something less amazing than foo" do
# ...
end
test "#do_something does Z" do
# ...
end
end
Mental Model
Tests as Specification
class MyThingTest < HermeticTestCase
test "#do_something with arg1 and arg2 does X" do
# ...
end
test "#foo does something amazing" do
# ...
end
test "#do_something does Y if param1 is nil" do
# ...
end
test "#bar does something less amazing than foo" do
# ...
end
test "#do_something does Z" do
# ...
end
end
Mental Model
class MyThing
def do_something(a, b)
#...
end
end
Tests as Specification
class MyThingTest < HermeticTestCase
test "#do_something with arg1 and arg2 does X" do
# ...
end
test "#foo does something amazing" do
# ...
end
test "#do_something does Y if param1 is nil" do
# ...
end
test "#bar does something less amazing than foo" do
# ...
end
test "#do_something does Z" do
# ...
end
end
Mental Model
class MyThing
def do_something(a, b)
#...
end
end
• Regroup related ideas (tests)
• Make it easier to identify that related tests have the same logic
• Make it easier to identify which part of a test does what
Build Mental Model Faster?
RSpock
• Testing framework piggybacking on Minitest
• Came to life from 2x Hack Days projects in 2018
• Goals:
• Optimize time to build mental model
• Optimize time to write tests
What is it?
• Number of Test Cases / Lines of Code
• Higher test density => related ideas are more grouped together
Measurement: Test Density
class UpdaterComparatorTest < HermeticTestCase
class DummyUpdater < BaseUpdater; end
# ... setup block
test "#compare with updater a < b returns -1" do
result = @comparator.compare(UpdaterA.new, UpdaterB.new)
assert_equal(-1, result)
end
test "#compare with updater a > b returns 1" do
result = @comparator.compare(UpdaterB.new, UpdaterA.new)
assert_equal(1, result)
end
test "#compare with updater a == b returns 0" do
result = @comparator.compare(UpdaterA.new, UpdaterA.new)
assert_equal(0, result)
end
test "#compare with a missing updater raises" do
assert_raises ArgumentError do
@comparator.compare(DummyUpdater.new, UpdaterA.new)
end
end
end
Minitest
class UpdaterComparatorTest < HermeticTestCase
class DummyUpdater < BaseUpdater; end
# ... setup block
test "#compare with updater a < b returns -1" do
result = @comparator.compare(UpdaterA.new, UpdaterB.new)
assert_equal(-1, result)
end
test "#compare with updater a > b returns 1" do
result = @comparator.compare(UpdaterB.new, UpdaterA.new)
assert_equal(1, result)
end
test "#compare with updater a == b returns 0" do
result = @comparator.compare(UpdaterA.new, UpdaterA.new)
assert_equal(0, result)
end
test "#compare with a missing updater raises" do
assert_raises ArgumentError do
@comparator.compare(DummyUpdater.new, UpdaterA.new)
end
end
end
transform!(RSpock::AST::Transformation)
class UpdaterComparatorTest < HermeticTestCase
class DummyUpdater < CheckoutUpdaters::BaseUpdater; end
# ... setup block
test "#compare #{updater1.class} with #{updater2.class} returns #{result}" do
Expect
@comparator.compare(updater1, updater2) == result
Where
updater1 | updater2 | result
UpdaterA.new | UpdaterB.new | -1
UpdaterB.new | UpdaterA.new | 1
UpdaterB.new | UpdaterB.new | 0
end
test "#compare with unknown updater raises" do
Expect
assert_raises ArgumentError do
@comparator.compare(updater1, updater2)
end
Where
updater1 | updater2
DummyUpdater.new | DummyUpdater.new
DummyUpdater.new | UpdaterA.new
UpdaterA.new | DummyUpdater.new
end
end
RSpockMinitest
class UpdaterComparatorTest < HermeticTestCase
class DummyUpdater < BaseUpdater; end
# ... setup block
test "#compare with updater a < b returns -1" do
result = @comparator.compare(UpdaterA.new, UpdaterB.new)
assert_equal(-1, result)
end
test "#compare with updater a > b returns 1" do
result = @comparator.compare(UpdaterB.new, UpdaterA.new)
assert_equal(1, result)
end
test "#compare with updater a == b returns 0" do
result = @comparator.compare(UpdaterA.new, UpdaterA.new)
assert_equal(0, result)
end
test "#compare with a missing updater raises" do
assert_raises ArgumentError do
@comparator.compare(DummyUpdater.new, UpdaterA.new)
end
end
end
transform!(RSpock::AST::Transformation)
class UpdaterComparatorTest < HermeticTestCase
class DummyUpdater < CheckoutUpdaters::BaseUpdater; end
# ... setup block
test "#compare #{updater1.class} with #{updater2.class} returns #{result}" do
Expect
@comparator.compare(updater1, updater2) == result
Where
updater1 | updater2 | result
UpdaterA.new | UpdaterB.new | -1
UpdaterB.new | UpdaterA.new | 1
UpdaterB.new | UpdaterB.new | 0
end
test "#compare with unknown updater raises" do
Expect
assert_raises ArgumentError do
@comparator.compare(updater1, updater2)
end
Where
updater1 | updater2
DummyUpdater.new | DummyUpdater.new
DummyUpdater.new | UpdaterA.new
UpdaterA.new | DummyUpdater.new
end
end
RSpockMinitest
class UpdaterComparatorTest < HermeticTestCase
class DummyUpdater < BaseUpdater; end
# ... setup block
test "#compare with updater a < b returns -1" do
result = @comparator.compare(UpdaterA.new, UpdaterB.new)
assert_equal(-1, result)
end
test "#compare with updater a > b returns 1" do
result = @comparator.compare(UpdaterB.new, UpdaterA.new)
assert_equal(1, result)
end
test "#compare with updater a == b returns 0" do
result = @comparator.compare(UpdaterA.new, UpdaterA.new)
assert_equal(0, result)
end
test "#compare with a missing updater raises" do
assert_raises ArgumentError do
@comparator.compare(DummyUpdater.new, UpdaterA.new)
end
end
end
transform!(RSpock::AST::Transformation)
class UpdaterComparatorTest < HermeticTestCase
class DummyUpdater < CheckoutUpdaters::BaseUpdater; end
# ... setup block
test "#compare #{updater1.class} with #{updater2.class} returns #{result}" do
Expect
@comparator.compare(updater1, updater2) == result
Where
updater1 | updater2 | result
UpdaterA.new | UpdaterB.new | -1
UpdaterB.new | UpdaterA.new | 1
UpdaterB.new | UpdaterB.new | 0
end
test "#compare with unknown updater raises" do
Expect
assert_raises ArgumentError do
@comparator.compare(updater1, updater2)
end
Where
updater1 | updater2
DummyUpdater.new | DummyUpdater.new
DummyUpdater.new | UpdaterA.new
UpdaterA.new | DummyUpdater.new
end
end
RSpockMinitest
class UpdaterComparatorTest < HermeticTestCase
class DummyUpdater < BaseUpdater; end
# ... setup block
test "#compare with updater a < b returns -1" do
result = @comparator.compare(UpdaterA.new, UpdaterB.new)
assert_equal(-1, result)
end
test "#compare with updater a > b returns 1" do
result = @comparator.compare(UpdaterB.new, UpdaterA.new)
assert_equal(1, result)
end
test "#compare with updater a == b returns 0" do
result = @comparator.compare(UpdaterA.new, UpdaterA.new)
assert_equal(0, result)
end
test "#compare with a missing updater raises" do
assert_raises ArgumentError do
@comparator.compare(DummyUpdater.new, UpdaterA.new)
end
end
end
transform!(RSpock::AST::Transformation)
class UpdaterComparatorTest < HermeticTestCase
class DummyUpdater < CheckoutUpdaters::BaseUpdater; end
# ... setup block
test "#compare #{updater1.class} with #{updater2.class} returns #{result}" do
Expect
@comparator.compare(updater1, updater2) == result
Where
updater1 | updater2 | result
UpdaterA.new | UpdaterB.new | -1
UpdaterB.new | UpdaterA.new | 1
UpdaterB.new | UpdaterB.new | 0
end
test "#compare with unknown updater raises" do
Expect
assert_raises ArgumentError do
@comparator.compare(updater1, updater2)
end
Where
updater1 | updater2
DummyUpdater.new | DummyUpdater.new
DummyUpdater.new | UpdaterA.new
UpdaterA.new | DummyUpdater.new
end
end
RSpockMinitest
class UpdaterComparatorTest < HermeticTestCase
class DummyUpdater < BaseUpdater; end
# ... setup block
test "#compare with updater a < b returns -1" do
result = @comparator.compare(UpdaterA.new, UpdaterB.new)
assert_equal(-1, result)
end
test "#compare with updater a > b returns 1" do
result = @comparator.compare(UpdaterB.new, UpdaterA.new)
assert_equal(1, result)
end
test "#compare with updater a == b returns 0" do
result = @comparator.compare(UpdaterA.new, UpdaterA.new)
assert_equal(0, result)
end
test "#compare with a missing updater raises" do
assert_raises ArgumentError do
@comparator.compare(DummyUpdater.new, UpdaterA.new)
end
end
end
transform!(RSpock::AST::Transformation)
class UpdaterComparatorTest < HermeticTestCase
class DummyUpdater < CheckoutUpdaters::BaseUpdater; end
# ... setup block
test "#compare #{updater1.class} with #{updater2.class} returns #{result}" do
Expect
@comparator.compare(updater1, updater2) == result
Where
updater1 | updater2 | result
UpdaterA.new | UpdaterB.new | -1
UpdaterB.new | UpdaterA.new | 1
UpdaterB.new | UpdaterB.new | 0
end
test "#compare with unknown updater raises" do
Expect
assert_raises ArgumentError do
@comparator.compare(updater1, updater2)
end
Where
updater1 | updater2
DummyUpdater.new | DummyUpdater.new
DummyUpdater.new | UpdaterA.new
UpdaterA.new | DummyUpdater.new
end
end
RSpockMinitest
4 26
Test Cases per Lines of Code
test cases w/o RSpock lines of code w/o RSpock
6 30test cases with RSpock lines of code with RSpock
0.15 0.20
Test Density
w/o RSpock with RSpock
33%improvement
Case Study:
Multi Location Inventory
Tests
18 268
Multi Location Inventory Tests
test cases w/o RSpock lines of code w/o RSpock
77 220test cases with RSpock lines of code with RSpock
0.07 0.35
Test Density
w/o RSpock with RSpock
400%improvement
20.3 54.5
Coverage
avg. hits per line w/o RSpock avg. hits per line with RSpock
98%test coverage for both
RSpock Code Blocks -> BDD Phases
Code Block BDD Phase
Given Setup
When Stimulus
Then Response
Expect
Stimulus +
Response
Cleanup Cleanup
How Does it Work?
RubyVM::InstructionSequence Hook
module RubyVM::InstructionSequence
def self.load_iseq(source_path)
# ...
end
end
Abstract Syntax Tree
1 + 2
int(1)
send(:+)
int(2)
Ruby Code
transform! annotation
transform!(RSpock::AST::Transformation)
class MyTest < Minitest::Test
# ...
end
RSpock Code Blocks
Given
Given "An empty Cart and a Product"
cart = Cart.new
product = Product.new
When
When "Adding a product"
cart.add_product(Product.new)
Then
Then "The product is added to the cart"
cart.products.size == 1
cart.products.first == product
Expect
When "Calling #abs on a negative number"
actual = -2.abs
Then "Value is positive"
actual == 2
Expect "absolute of -2 is 2"
-2.abs == 2
Using Expect
When + Then
• Use When + Then to describe methods with side-effects
• Use Expect to describe purely functional methods (query methods)
Expect: Rule of Thumb
Cleanup
Given "Open the file"
file = File.new("/invalid/file/path") # raises
# other blocks...
Cleanup
# Use safe navigation operator, since +file+ is nil if an error occurred.
file&.close
Where
test "#{a} XOR #{b} results in #{r}" do
Expect
a ^ b == r
Where
a | b | r
0 | 0 | 0
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0
end
Code Blocks
• Describes ouputs in terms of possible inputs
• Common approach in propositional logic and boolean algebra
Truth Table
Truth Table: XOR
case in1 in2 out
1 0 0 0
2 0 1 1
3 1 0 1
4 1 1 0
• Ordering test cases makes them easier to find and reason about.
• Ordered data table makes it easier to understand test cases.
• Recommend to order by boolean increment.
Where Blocks
Truth Table Generator
$ rake rspock:truth_table -- a=-1,0,1 b=-1,0,1 r='?'
a | b | r
-1 | -1 | '?'
-1 | 0 | '?'
-1 | 1 | '?'
0 | -1 | '?'
0 | 0 | '?'
0 | 1 | '?'
1 | -1 | '?'
1 | 0 | '?'
1 | 1 | '?'
Why do this?
test "#{a} XOR #{b} results in #{r}" do
Expect
a ^ b == r
Where
a | b | r
0 | 0 | 0
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0
end
test "#{a} XOR #{b} results in #{r}" do
Expect
a ^ b == r
Where
a | b | r
0 | 0 | 0
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0
end
When you can do this:
[
{a: 0, b: 0, r: 0},
{a: 0, b: 1, r: 1},
{a: 1, b: 0, r: 1},
{a: 1, b: 1, r: 1},
].each do |a:, b:, r:|
test "#{a} XOR #{b} results in #{r}" do
assert_equal r, a ^ b
end
end
Why do this?
• Executed code != Source code
• Debugging in Pry has slightly different code
What’s the catch?
• Better tooling support (i.e. Pry)
• Open-sourcing the project
• More features!!
What’s next?
• GitHub: https://github.com/rspockframework/rspock
• RubyGems: https://rubygems.org/gems/rspock
I’m In! How can I use it?
Questions?

More Related Content

What's hot

Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021
Scott Keck-Warren
 
PgTAP Best Practices
PgTAP Best PracticesPgTAP Best Practices
PgTAP Best Practices
David Wheeler
 
Unit Test Your Database
Unit Test Your DatabaseUnit Test Your Database
Unit Test Your Database
David Wheeler
 
Finding the Right Testing Tool for the Job
Finding the Right Testing Tool for the JobFinding the Right Testing Tool for the Job
Finding the Right Testing Tool for the Job
CiaranMcNulty
 
TDD, BDD, RSpec
TDD, BDD, RSpecTDD, BDD, RSpec
TDD, BDD, RSpec
Nascenia IT
 
AngularJS Unit Testing w/Karma and Jasmine
AngularJS Unit Testing w/Karma and JasmineAngularJS Unit Testing w/Karma and Jasmine
AngularJS Unit Testing w/Karma and Jasmine
foxp2code
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
Lean Teams Consultancy
 
Angular testing
Angular testingAngular testing
Angular testing
Raissa Ferreira
 
pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기
Yeongseon Choe
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
Sheeju Alex
 
From typing the test to testing the type
From typing the test to testing the typeFrom typing the test to testing the type
From typing the test to testing the type
Wim Godden
 
Test-Driven Development of AngularJS Applications
Test-Driven Development of AngularJS ApplicationsTest-Driven Development of AngularJS Applications
Test-Driven Development of AngularJS Applications
FITC
 
Apex Testing and Best Practices
Apex Testing and Best PracticesApex Testing and Best Practices
Apex Testing and Best Practices
Jitendra Zaa
 
Testing Legacy Rails Apps
Testing Legacy Rails AppsTesting Legacy Rails Apps
Testing Legacy Rails Apps
Rabble .
 
AngularJS Testing Strategies
AngularJS Testing StrategiesAngularJS Testing Strategies
AngularJS Testing Strategies
njpst8
 
TDD
TDDTDD
Describe's Full of It's
Describe's Full of It'sDescribe's Full of It's
Describe's Full of It's
Jim Lynch
 
Creating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf USCreating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf US
Annyce Davis
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
scidept
 
Example First / A Sane Test-Driven Approach to Programming
Example First / A Sane Test-Driven Approach to ProgrammingExample First / A Sane Test-Driven Approach to Programming
Example First / A Sane Test-Driven Approach to Programming
Jonathan Acker
 

What's hot (20)

Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021
 
PgTAP Best Practices
PgTAP Best PracticesPgTAP Best Practices
PgTAP Best Practices
 
Unit Test Your Database
Unit Test Your DatabaseUnit Test Your Database
Unit Test Your Database
 
Finding the Right Testing Tool for the Job
Finding the Right Testing Tool for the JobFinding the Right Testing Tool for the Job
Finding the Right Testing Tool for the Job
 
TDD, BDD, RSpec
TDD, BDD, RSpecTDD, BDD, RSpec
TDD, BDD, RSpec
 
AngularJS Unit Testing w/Karma and Jasmine
AngularJS Unit Testing w/Karma and JasmineAngularJS Unit Testing w/Karma and Jasmine
AngularJS Unit Testing w/Karma and Jasmine
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
 
Angular testing
Angular testingAngular testing
Angular testing
 
pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
From typing the test to testing the type
From typing the test to testing the typeFrom typing the test to testing the type
From typing the test to testing the type
 
Test-Driven Development of AngularJS Applications
Test-Driven Development of AngularJS ApplicationsTest-Driven Development of AngularJS Applications
Test-Driven Development of AngularJS Applications
 
Apex Testing and Best Practices
Apex Testing and Best PracticesApex Testing and Best Practices
Apex Testing and Best Practices
 
Testing Legacy Rails Apps
Testing Legacy Rails AppsTesting Legacy Rails Apps
Testing Legacy Rails Apps
 
AngularJS Testing Strategies
AngularJS Testing StrategiesAngularJS Testing Strategies
AngularJS Testing Strategies
 
TDD
TDDTDD
TDD
 
Describe's Full of It's
Describe's Full of It'sDescribe's Full of It's
Describe's Full of It's
 
Creating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf USCreating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf US
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 
Example First / A Sane Test-Driven Approach to Programming
Example First / A Sane Test-Driven Approach to ProgrammingExample First / A Sane Test-Driven Approach to Programming
Example First / A Sane Test-Driven Approach to Programming
 

Similar to RSpock Testing Framework for Ruby

Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
Dave Cross
 
Tdd for BT E2E test community
Tdd for BT E2E test communityTdd for BT E2E test community
Tdd for BT E2E test community
Kerry Buckley
 
Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8
Frédéric Delorme
 
Ruby on Rails testing with Rspec
Ruby on Rails testing with RspecRuby on Rails testing with Rspec
Ruby on Rails testing with Rspec
Bunlong Van
 
Why ruby
Why rubyWhy ruby
Why ruby
rstankov
 
PHPUnit testing to Zend_Test
PHPUnit testing to Zend_TestPHPUnit testing to Zend_Test
PHPUnit testing to Zend_Test
Michelangelo van Dam
 
Php Unit With Zend Framework Zendcon09
Php Unit With Zend Framework   Zendcon09Php Unit With Zend Framework   Zendcon09
Php Unit With Zend Framework Zendcon09
Michelangelo van Dam
 
Антипаттерны модульного тестирования
Антипаттерны модульного тестированияАнтипаттерны модульного тестирования
Антипаттерны модульного тестирования
MitinPavel
 
Introduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitIntroduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnit
Michelangelo van Dam
 
Refactoring Ruby Code
Refactoring Ruby CodeRefactoring Ruby Code
Refactoring Ruby Code
Caike Souza
 
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
Rodolfo Carvalho
 
Pro Java Fx – Developing Enterprise Applications
Pro Java Fx – Developing Enterprise ApplicationsPro Java Fx – Developing Enterprise Applications
Pro Java Fx – Developing Enterprise Applications
Stephen Chin
 
Developer Testing Tools Roundup
Developer Testing Tools RoundupDeveloper Testing Tools Roundup
Developer Testing Tools Roundup
John Ferguson Smart Limited
 
Testing in Django
Testing in DjangoTesting in Django
Testing in Django
Kevin Harvey
 
MT_01_unittest_python.pdf
MT_01_unittest_python.pdfMT_01_unittest_python.pdf
MT_01_unittest_python.pdf
Hans Jones
 
Test Driven Development with PHPUnit
Test Driven Development with PHPUnitTest Driven Development with PHPUnit
Test Driven Development with PHPUnit
Mindfire Solutions
 
New Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian BergmannNew Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian Bergmann
dpc
 
Developer testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticDeveloper testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing Fanatic
LB Denker
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
rstankov
 
Mutation Testing - Ruby Edition
Mutation Testing - Ruby EditionMutation Testing - Ruby Edition
Mutation Testing - Ruby Edition
Chris Sinjakli
 

Similar to RSpock Testing Framework for Ruby (20)

Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 
Tdd for BT E2E test community
Tdd for BT E2E test communityTdd for BT E2E test community
Tdd for BT E2E test community
 
Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8
 
Ruby on Rails testing with Rspec
Ruby on Rails testing with RspecRuby on Rails testing with Rspec
Ruby on Rails testing with Rspec
 
Why ruby
Why rubyWhy ruby
Why ruby
 
PHPUnit testing to Zend_Test
PHPUnit testing to Zend_TestPHPUnit testing to Zend_Test
PHPUnit testing to Zend_Test
 
Php Unit With Zend Framework Zendcon09
Php Unit With Zend Framework   Zendcon09Php Unit With Zend Framework   Zendcon09
Php Unit With Zend Framework Zendcon09
 
Антипаттерны модульного тестирования
Антипаттерны модульного тестированияАнтипаттерны модульного тестирования
Антипаттерны модульного тестирования
 
Introduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnitIntroduction to Unit Testing with PHPUnit
Introduction to Unit Testing with PHPUnit
 
Refactoring Ruby Code
Refactoring Ruby CodeRefactoring Ruby Code
Refactoring Ruby Code
 
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
 
Pro Java Fx – Developing Enterprise Applications
Pro Java Fx – Developing Enterprise ApplicationsPro Java Fx – Developing Enterprise Applications
Pro Java Fx – Developing Enterprise Applications
 
Developer Testing Tools Roundup
Developer Testing Tools RoundupDeveloper Testing Tools Roundup
Developer Testing Tools Roundup
 
Testing in Django
Testing in DjangoTesting in Django
Testing in Django
 
MT_01_unittest_python.pdf
MT_01_unittest_python.pdfMT_01_unittest_python.pdf
MT_01_unittest_python.pdf
 
Test Driven Development with PHPUnit
Test Driven Development with PHPUnitTest Driven Development with PHPUnit
Test Driven Development with PHPUnit
 
New Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian BergmannNew Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian Bergmann
 
Developer testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticDeveloper testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing Fanatic
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Mutation Testing - Ruby Edition
Mutation Testing - Ruby EditionMutation Testing - Ruby Edition
Mutation Testing - Ruby Edition
 

More from Brice Argenson

Serverless Applications
Serverless ApplicationsServerless Applications
Serverless Applications
Brice Argenson
 
Serverless - Lunch&Learn CleverToday - Mars 2017
Serverless - Lunch&Learn CleverToday - Mars 2017Serverless - Lunch&Learn CleverToday - Mars 2017
Serverless - Lunch&Learn CleverToday - Mars 2017
Brice Argenson
 
Docker 1.13 - Docker meetup février 2017
Docker 1.13 - Docker meetup février 2017Docker 1.13 - Docker meetup février 2017
Docker 1.13 - Docker meetup février 2017
Brice Argenson
 
Docker 1.12 & Swarm Mode [Montreal Docker Meetup Sept. 2016]
Docker 1.12 & Swarm Mode [Montreal Docker Meetup Sept. 2016]Docker 1.12 & Swarm Mode [Montreal Docker Meetup Sept. 2016]
Docker 1.12 & Swarm Mode [Montreal Docker Meetup Sept. 2016]
Brice Argenson
 
Packagez et déployez vos applications avec Docker - Montréal CloudFoundry Mee...
Packagez et déployez vos applications avec Docker - Montréal CloudFoundry Mee...Packagez et déployez vos applications avec Docker - Montréal CloudFoundry Mee...
Packagez et déployez vos applications avec Docker - Montréal CloudFoundry Mee...
Brice Argenson
 
The Patterns to boost your time to market - An introduction to DevOps
The Patterns to boost your time to market - An introduction to DevOpsThe Patterns to boost your time to market - An introduction to DevOps
The Patterns to boost your time to market - An introduction to DevOps
Brice Argenson
 
Introduction to Continuous Integration with Jenkins
Introduction to Continuous Integration with JenkinsIntroduction to Continuous Integration with Jenkins
Introduction to Continuous Integration with Jenkins
Brice Argenson
 
Java EE - Servlets API
Java EE - Servlets APIJava EE - Servlets API
Java EE - Servlets API
Brice Argenson
 
JS-Everywhere - SSE Hands-on
JS-Everywhere - SSE Hands-onJS-Everywhere - SSE Hands-on
JS-Everywhere - SSE Hands-on
Brice Argenson
 
JS-Everywhere - LocalStorage Hands-on
JS-Everywhere - LocalStorage Hands-onJS-Everywhere - LocalStorage Hands-on
JS-Everywhere - LocalStorage Hands-on
Brice Argenson
 
Effective Java
Effective JavaEffective Java
Effective Java
Brice Argenson
 
Soutenance mémoire : Implémentation d'un DSL en entreprise
Soutenance mémoire : Implémentation d'un DSL en entrepriseSoutenance mémoire : Implémentation d'un DSL en entreprise
Soutenance mémoire : Implémentation d'un DSL en entrepriseBrice Argenson
 

More from Brice Argenson (12)

Serverless Applications
Serverless ApplicationsServerless Applications
Serverless Applications
 
Serverless - Lunch&Learn CleverToday - Mars 2017
Serverless - Lunch&Learn CleverToday - Mars 2017Serverless - Lunch&Learn CleverToday - Mars 2017
Serverless - Lunch&Learn CleverToday - Mars 2017
 
Docker 1.13 - Docker meetup février 2017
Docker 1.13 - Docker meetup février 2017Docker 1.13 - Docker meetup février 2017
Docker 1.13 - Docker meetup février 2017
 
Docker 1.12 & Swarm Mode [Montreal Docker Meetup Sept. 2016]
Docker 1.12 & Swarm Mode [Montreal Docker Meetup Sept. 2016]Docker 1.12 & Swarm Mode [Montreal Docker Meetup Sept. 2016]
Docker 1.12 & Swarm Mode [Montreal Docker Meetup Sept. 2016]
 
Packagez et déployez vos applications avec Docker - Montréal CloudFoundry Mee...
Packagez et déployez vos applications avec Docker - Montréal CloudFoundry Mee...Packagez et déployez vos applications avec Docker - Montréal CloudFoundry Mee...
Packagez et déployez vos applications avec Docker - Montréal CloudFoundry Mee...
 
The Patterns to boost your time to market - An introduction to DevOps
The Patterns to boost your time to market - An introduction to DevOpsThe Patterns to boost your time to market - An introduction to DevOps
The Patterns to boost your time to market - An introduction to DevOps
 
Introduction to Continuous Integration with Jenkins
Introduction to Continuous Integration with JenkinsIntroduction to Continuous Integration with Jenkins
Introduction to Continuous Integration with Jenkins
 
Java EE - Servlets API
Java EE - Servlets APIJava EE - Servlets API
Java EE - Servlets API
 
JS-Everywhere - SSE Hands-on
JS-Everywhere - SSE Hands-onJS-Everywhere - SSE Hands-on
JS-Everywhere - SSE Hands-on
 
JS-Everywhere - LocalStorage Hands-on
JS-Everywhere - LocalStorage Hands-onJS-Everywhere - LocalStorage Hands-on
JS-Everywhere - LocalStorage Hands-on
 
Effective Java
Effective JavaEffective Java
Effective Java
 
Soutenance mémoire : Implémentation d'un DSL en entreprise
Soutenance mémoire : Implémentation d'un DSL en entrepriseSoutenance mémoire : Implémentation d'un DSL en entreprise
Soutenance mémoire : Implémentation d'un DSL en entreprise
 

Recently uploaded

Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdfBaha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid
 
TheFutureIsDynamic-BoxLang-CFCamp2024.pdf
TheFutureIsDynamic-BoxLang-CFCamp2024.pdfTheFutureIsDynamic-BoxLang-CFCamp2024.pdf
TheFutureIsDynamic-BoxLang-CFCamp2024.pdf
Ortus Solutions, Corp
 
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptxOperational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
sandeepmenon62
 
Trailhead Talks_ Journey of an All-Star Ranger .pptx
Trailhead Talks_ Journey of an All-Star Ranger .pptxTrailhead Talks_ Journey of an All-Star Ranger .pptx
Trailhead Talks_ Journey of an All-Star Ranger .pptx
ImtiazBinMohiuddin
 
ppt on the brain chip neuralink.pptx
ppt  on   the brain  chip neuralink.pptxppt  on   the brain  chip neuralink.pptx
ppt on the brain chip neuralink.pptx
Reetu63
 
Why Apache Kafka Clusters Are Like Galaxies (And Other Cosmic Kafka Quandarie...
Why Apache Kafka Clusters Are Like Galaxies (And Other Cosmic Kafka Quandarie...Why Apache Kafka Clusters Are Like Galaxies (And Other Cosmic Kafka Quandarie...
Why Apache Kafka Clusters Are Like Galaxies (And Other Cosmic Kafka Quandarie...
Paul Brebner
 
Call Girls Bangalore🔥7023059433🔥Best Profile Escorts in Bangalore Available 24/7
Call Girls Bangalore🔥7023059433🔥Best Profile Escorts in Bangalore Available 24/7Call Girls Bangalore🔥7023059433🔥Best Profile Escorts in Bangalore Available 24/7
Call Girls Bangalore🔥7023059433🔥Best Profile Escorts in Bangalore Available 24/7
manji sharman06
 
42 Ways to Generate Real Estate Leads - Sellxpert
42 Ways to Generate Real Estate Leads - Sellxpert42 Ways to Generate Real Estate Leads - Sellxpert
42 Ways to Generate Real Estate Leads - Sellxpert
vaishalijagtap12
 
Upturn India Technologies - Web development company in Nashik
Upturn India Technologies - Web development company in NashikUpturn India Technologies - Web development company in Nashik
Upturn India Technologies - Web development company in Nashik
Upturn India Technologies
 
Hands-on with Apache Druid: Installation & Data Ingestion Steps
Hands-on with Apache Druid: Installation & Data Ingestion StepsHands-on with Apache Druid: Installation & Data Ingestion Steps
Hands-on with Apache Druid: Installation & Data Ingestion Steps
servicesNitor
 
What’s New in VictoriaLogs - Q2 2024 Update
What’s New in VictoriaLogs - Q2 2024 UpdateWhat’s New in VictoriaLogs - Q2 2024 Update
What’s New in VictoriaLogs - Q2 2024 Update
VictoriaMetrics
 
Ensuring Efficiency and Speed with Practical Solutions for Clinical Operations
Ensuring Efficiency and Speed with Practical Solutions for Clinical OperationsEnsuring Efficiency and Speed with Practical Solutions for Clinical Operations
Ensuring Efficiency and Speed with Practical Solutions for Clinical Operations
OnePlan Solutions
 
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
campbellclarkson
 
Building the Ideal CI-CD Pipeline_ Achieving Visual Perfection
Building the Ideal CI-CD Pipeline_ Achieving Visual PerfectionBuilding the Ideal CI-CD Pipeline_ Achieving Visual Perfection
Building the Ideal CI-CD Pipeline_ Achieving Visual Perfection
Applitools
 
How GenAI Can Improve Supplier Performance Management.pdf
How GenAI Can Improve Supplier Performance Management.pdfHow GenAI Can Improve Supplier Performance Management.pdf
How GenAI Can Improve Supplier Performance Management.pdf
Zycus
 
A Comprehensive Guide on Implementing Real-World Mobile Testing Strategies fo...
A Comprehensive Guide on Implementing Real-World Mobile Testing Strategies fo...A Comprehensive Guide on Implementing Real-World Mobile Testing Strategies fo...
A Comprehensive Guide on Implementing Real-World Mobile Testing Strategies fo...
kalichargn70th171
 
Hyperledger Besu 빨리 따라하기 (Private Networks)
Hyperledger Besu 빨리 따라하기 (Private Networks)Hyperledger Besu 빨리 따라하기 (Private Networks)
Hyperledger Besu 빨리 따라하기 (Private Networks)
wonyong hwang
 
What’s new in VictoriaMetrics - Q2 2024 Update
What’s new in VictoriaMetrics - Q2 2024 UpdateWhat’s new in VictoriaMetrics - Q2 2024 Update
What’s new in VictoriaMetrics - Q2 2024 Update
VictoriaMetrics
 
Superpower Your Apache Kafka Applications Development with Complementary Open...
Superpower Your Apache Kafka Applications Development with Complementary Open...Superpower Your Apache Kafka Applications Development with Complementary Open...
Superpower Your Apache Kafka Applications Development with Complementary Open...
Paul Brebner
 

Recently uploaded (20)

Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdfBaha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
Baha Majid WCA4Z IBM Z Customer Council Boston June 2024.pdf
 
TheFutureIsDynamic-BoxLang-CFCamp2024.pdf
TheFutureIsDynamic-BoxLang-CFCamp2024.pdfTheFutureIsDynamic-BoxLang-CFCamp2024.pdf
TheFutureIsDynamic-BoxLang-CFCamp2024.pdf
 
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptxOperational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
Operational ease MuleSoft and Salesforce Service Cloud Solution v1.0.pptx
 
Trailhead Talks_ Journey of an All-Star Ranger .pptx
Trailhead Talks_ Journey of an All-Star Ranger .pptxTrailhead Talks_ Journey of an All-Star Ranger .pptx
Trailhead Talks_ Journey of an All-Star Ranger .pptx
 
ppt on the brain chip neuralink.pptx
ppt  on   the brain  chip neuralink.pptxppt  on   the brain  chip neuralink.pptx
ppt on the brain chip neuralink.pptx
 
Why Apache Kafka Clusters Are Like Galaxies (And Other Cosmic Kafka Quandarie...
Why Apache Kafka Clusters Are Like Galaxies (And Other Cosmic Kafka Quandarie...Why Apache Kafka Clusters Are Like Galaxies (And Other Cosmic Kafka Quandarie...
Why Apache Kafka Clusters Are Like Galaxies (And Other Cosmic Kafka Quandarie...
 
Call Girls Bangalore🔥7023059433🔥Best Profile Escorts in Bangalore Available 24/7
Call Girls Bangalore🔥7023059433🔥Best Profile Escorts in Bangalore Available 24/7Call Girls Bangalore🔥7023059433🔥Best Profile Escorts in Bangalore Available 24/7
Call Girls Bangalore🔥7023059433🔥Best Profile Escorts in Bangalore Available 24/7
 
42 Ways to Generate Real Estate Leads - Sellxpert
42 Ways to Generate Real Estate Leads - Sellxpert42 Ways to Generate Real Estate Leads - Sellxpert
42 Ways to Generate Real Estate Leads - Sellxpert
 
Upturn India Technologies - Web development company in Nashik
Upturn India Technologies - Web development company in NashikUpturn India Technologies - Web development company in Nashik
Upturn India Technologies - Web development company in Nashik
 
Hands-on with Apache Druid: Installation & Data Ingestion Steps
Hands-on with Apache Druid: Installation & Data Ingestion StepsHands-on with Apache Druid: Installation & Data Ingestion Steps
Hands-on with Apache Druid: Installation & Data Ingestion Steps
 
What’s New in VictoriaLogs - Q2 2024 Update
What’s New in VictoriaLogs - Q2 2024 UpdateWhat’s New in VictoriaLogs - Q2 2024 Update
What’s New in VictoriaLogs - Q2 2024 Update
 
Ensuring Efficiency and Speed with Practical Solutions for Clinical Operations
Ensuring Efficiency and Speed with Practical Solutions for Clinical OperationsEnsuring Efficiency and Speed with Practical Solutions for Clinical Operations
Ensuring Efficiency and Speed with Practical Solutions for Clinical Operations
 
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
🏎️Tech Transformation: DevOps Insights from the Experts 👩‍💻
 
Building the Ideal CI-CD Pipeline_ Achieving Visual Perfection
Building the Ideal CI-CD Pipeline_ Achieving Visual PerfectionBuilding the Ideal CI-CD Pipeline_ Achieving Visual Perfection
Building the Ideal CI-CD Pipeline_ Achieving Visual Perfection
 
How GenAI Can Improve Supplier Performance Management.pdf
How GenAI Can Improve Supplier Performance Management.pdfHow GenAI Can Improve Supplier Performance Management.pdf
How GenAI Can Improve Supplier Performance Management.pdf
 
A Comprehensive Guide on Implementing Real-World Mobile Testing Strategies fo...
A Comprehensive Guide on Implementing Real-World Mobile Testing Strategies fo...A Comprehensive Guide on Implementing Real-World Mobile Testing Strategies fo...
A Comprehensive Guide on Implementing Real-World Mobile Testing Strategies fo...
 
Hyperledger Besu 빨리 따라하기 (Private Networks)
Hyperledger Besu 빨리 따라하기 (Private Networks)Hyperledger Besu 빨리 따라하기 (Private Networks)
Hyperledger Besu 빨리 따라하기 (Private Networks)
 
bgiolcb
bgiolcbbgiolcb
bgiolcb
 
What’s new in VictoriaMetrics - Q2 2024 Update
What’s new in VictoriaMetrics - Q2 2024 UpdateWhat’s new in VictoriaMetrics - Q2 2024 Update
What’s new in VictoriaMetrics - Q2 2024 Update
 
Superpower Your Apache Kafka Applications Development with Complementary Open...
Superpower Your Apache Kafka Applications Development with Complementary Open...Superpower Your Apache Kafka Applications Development with Complementary Open...
Superpower Your Apache Kafka Applications Development with Complementary Open...
 

RSpock Testing Framework for Ruby

  • 2. • 80% reading code • 20% writing code • Some even say closer to 10:1 Read / Write Code
  • 3. “I Have a Dream” class MyThing # ... def do_something(a, b) # Implementation details... end end
  • 4. “I Have a Dream” class MyThing extend(T::Sig) sig { params(a: Integer, b: Integer).returns(String) } def do_something(a, b) # Implementation details... end end
  • 5. “I Have a Dream” class MyThing extend(T::Sig) # Documentation sig { params(a: Integer, b: Integer).returns(String) } def do_something(a, b) # Implementation details... end end
  • 6. class MyThing def do_something(a, b) #... end end Mental Model
  • 7. class MyThing def do_something(a, b) #... end end Tests as Specification class MyThingTest < HermeticTestCase test "#do_something with arg1 and arg2 does X" do # ... end test "#foo does something amazing" do # ... end test "#do_something does Y if param1 is nil" do # ... end test "#bar does something less amazing than foo" do # ... end test "#do_something does Z" do # ... end end Mental Model
  • 8. Tests as Specification class MyThingTest < HermeticTestCase test "#do_something with arg1 and arg2 does X" do # ... end test "#foo does something amazing" do # ... end test "#do_something does Y if param1 is nil" do # ... end test "#bar does something less amazing than foo" do # ... end test "#do_something does Z" do # ... end end Mental Model class MyThing def do_something(a, b) #... end end
  • 9. Tests as Specification class MyThingTest < HermeticTestCase test "#do_something with arg1 and arg2 does X" do # ... end test "#foo does something amazing" do # ... end test "#do_something does Y if param1 is nil" do # ... end test "#bar does something less amazing than foo" do # ... end test "#do_something does Z" do # ... end end Mental Model class MyThing def do_something(a, b) #... end end
  • 10. • Regroup related ideas (tests) • Make it easier to identify that related tests have the same logic • Make it easier to identify which part of a test does what Build Mental Model Faster?
  • 12. • Testing framework piggybacking on Minitest • Came to life from 2x Hack Days projects in 2018 • Goals: • Optimize time to build mental model • Optimize time to write tests What is it?
  • 13. • Number of Test Cases / Lines of Code • Higher test density => related ideas are more grouped together Measurement: Test Density
  • 14. class UpdaterComparatorTest < HermeticTestCase class DummyUpdater < BaseUpdater; end # ... setup block test "#compare with updater a < b returns -1" do result = @comparator.compare(UpdaterA.new, UpdaterB.new) assert_equal(-1, result) end test "#compare with updater a > b returns 1" do result = @comparator.compare(UpdaterB.new, UpdaterA.new) assert_equal(1, result) end test "#compare with updater a == b returns 0" do result = @comparator.compare(UpdaterA.new, UpdaterA.new) assert_equal(0, result) end test "#compare with a missing updater raises" do assert_raises ArgumentError do @comparator.compare(DummyUpdater.new, UpdaterA.new) end end end Minitest
  • 15. class UpdaterComparatorTest < HermeticTestCase class DummyUpdater < BaseUpdater; end # ... setup block test "#compare with updater a < b returns -1" do result = @comparator.compare(UpdaterA.new, UpdaterB.new) assert_equal(-1, result) end test "#compare with updater a > b returns 1" do result = @comparator.compare(UpdaterB.new, UpdaterA.new) assert_equal(1, result) end test "#compare with updater a == b returns 0" do result = @comparator.compare(UpdaterA.new, UpdaterA.new) assert_equal(0, result) end test "#compare with a missing updater raises" do assert_raises ArgumentError do @comparator.compare(DummyUpdater.new, UpdaterA.new) end end end transform!(RSpock::AST::Transformation) class UpdaterComparatorTest < HermeticTestCase class DummyUpdater < CheckoutUpdaters::BaseUpdater; end # ... setup block test "#compare #{updater1.class} with #{updater2.class} returns #{result}" do Expect @comparator.compare(updater1, updater2) == result Where updater1 | updater2 | result UpdaterA.new | UpdaterB.new | -1 UpdaterB.new | UpdaterA.new | 1 UpdaterB.new | UpdaterB.new | 0 end test "#compare with unknown updater raises" do Expect assert_raises ArgumentError do @comparator.compare(updater1, updater2) end Where updater1 | updater2 DummyUpdater.new | DummyUpdater.new DummyUpdater.new | UpdaterA.new UpdaterA.new | DummyUpdater.new end end RSpockMinitest
  • 16. class UpdaterComparatorTest < HermeticTestCase class DummyUpdater < BaseUpdater; end # ... setup block test "#compare with updater a < b returns -1" do result = @comparator.compare(UpdaterA.new, UpdaterB.new) assert_equal(-1, result) end test "#compare with updater a > b returns 1" do result = @comparator.compare(UpdaterB.new, UpdaterA.new) assert_equal(1, result) end test "#compare with updater a == b returns 0" do result = @comparator.compare(UpdaterA.new, UpdaterA.new) assert_equal(0, result) end test "#compare with a missing updater raises" do assert_raises ArgumentError do @comparator.compare(DummyUpdater.new, UpdaterA.new) end end end transform!(RSpock::AST::Transformation) class UpdaterComparatorTest < HermeticTestCase class DummyUpdater < CheckoutUpdaters::BaseUpdater; end # ... setup block test "#compare #{updater1.class} with #{updater2.class} returns #{result}" do Expect @comparator.compare(updater1, updater2) == result Where updater1 | updater2 | result UpdaterA.new | UpdaterB.new | -1 UpdaterB.new | UpdaterA.new | 1 UpdaterB.new | UpdaterB.new | 0 end test "#compare with unknown updater raises" do Expect assert_raises ArgumentError do @comparator.compare(updater1, updater2) end Where updater1 | updater2 DummyUpdater.new | DummyUpdater.new DummyUpdater.new | UpdaterA.new UpdaterA.new | DummyUpdater.new end end RSpockMinitest
  • 17. class UpdaterComparatorTest < HermeticTestCase class DummyUpdater < BaseUpdater; end # ... setup block test "#compare with updater a < b returns -1" do result = @comparator.compare(UpdaterA.new, UpdaterB.new) assert_equal(-1, result) end test "#compare with updater a > b returns 1" do result = @comparator.compare(UpdaterB.new, UpdaterA.new) assert_equal(1, result) end test "#compare with updater a == b returns 0" do result = @comparator.compare(UpdaterA.new, UpdaterA.new) assert_equal(0, result) end test "#compare with a missing updater raises" do assert_raises ArgumentError do @comparator.compare(DummyUpdater.new, UpdaterA.new) end end end transform!(RSpock::AST::Transformation) class UpdaterComparatorTest < HermeticTestCase class DummyUpdater < CheckoutUpdaters::BaseUpdater; end # ... setup block test "#compare #{updater1.class} with #{updater2.class} returns #{result}" do Expect @comparator.compare(updater1, updater2) == result Where updater1 | updater2 | result UpdaterA.new | UpdaterB.new | -1 UpdaterB.new | UpdaterA.new | 1 UpdaterB.new | UpdaterB.new | 0 end test "#compare with unknown updater raises" do Expect assert_raises ArgumentError do @comparator.compare(updater1, updater2) end Where updater1 | updater2 DummyUpdater.new | DummyUpdater.new DummyUpdater.new | UpdaterA.new UpdaterA.new | DummyUpdater.new end end RSpockMinitest
  • 18. class UpdaterComparatorTest < HermeticTestCase class DummyUpdater < BaseUpdater; end # ... setup block test "#compare with updater a < b returns -1" do result = @comparator.compare(UpdaterA.new, UpdaterB.new) assert_equal(-1, result) end test "#compare with updater a > b returns 1" do result = @comparator.compare(UpdaterB.new, UpdaterA.new) assert_equal(1, result) end test "#compare with updater a == b returns 0" do result = @comparator.compare(UpdaterA.new, UpdaterA.new) assert_equal(0, result) end test "#compare with a missing updater raises" do assert_raises ArgumentError do @comparator.compare(DummyUpdater.new, UpdaterA.new) end end end transform!(RSpock::AST::Transformation) class UpdaterComparatorTest < HermeticTestCase class DummyUpdater < CheckoutUpdaters::BaseUpdater; end # ... setup block test "#compare #{updater1.class} with #{updater2.class} returns #{result}" do Expect @comparator.compare(updater1, updater2) == result Where updater1 | updater2 | result UpdaterA.new | UpdaterB.new | -1 UpdaterB.new | UpdaterA.new | 1 UpdaterB.new | UpdaterB.new | 0 end test "#compare with unknown updater raises" do Expect assert_raises ArgumentError do @comparator.compare(updater1, updater2) end Where updater1 | updater2 DummyUpdater.new | DummyUpdater.new DummyUpdater.new | UpdaterA.new UpdaterA.new | DummyUpdater.new end end RSpockMinitest
  • 19. class UpdaterComparatorTest < HermeticTestCase class DummyUpdater < BaseUpdater; end # ... setup block test "#compare with updater a < b returns -1" do result = @comparator.compare(UpdaterA.new, UpdaterB.new) assert_equal(-1, result) end test "#compare with updater a > b returns 1" do result = @comparator.compare(UpdaterB.new, UpdaterA.new) assert_equal(1, result) end test "#compare with updater a == b returns 0" do result = @comparator.compare(UpdaterA.new, UpdaterA.new) assert_equal(0, result) end test "#compare with a missing updater raises" do assert_raises ArgumentError do @comparator.compare(DummyUpdater.new, UpdaterA.new) end end end transform!(RSpock::AST::Transformation) class UpdaterComparatorTest < HermeticTestCase class DummyUpdater < CheckoutUpdaters::BaseUpdater; end # ... setup block test "#compare #{updater1.class} with #{updater2.class} returns #{result}" do Expect @comparator.compare(updater1, updater2) == result Where updater1 | updater2 | result UpdaterA.new | UpdaterB.new | -1 UpdaterB.new | UpdaterA.new | 1 UpdaterB.new | UpdaterB.new | 0 end test "#compare with unknown updater raises" do Expect assert_raises ArgumentError do @comparator.compare(updater1, updater2) end Where updater1 | updater2 DummyUpdater.new | DummyUpdater.new DummyUpdater.new | UpdaterA.new UpdaterA.new | DummyUpdater.new end end RSpockMinitest
  • 20. 4 26 Test Cases per Lines of Code test cases w/o RSpock lines of code w/o RSpock 6 30test cases with RSpock lines of code with RSpock
  • 21. 0.15 0.20 Test Density w/o RSpock with RSpock 33%improvement
  • 22. Case Study: Multi Location Inventory Tests
  • 23. 18 268 Multi Location Inventory Tests test cases w/o RSpock lines of code w/o RSpock 77 220test cases with RSpock lines of code with RSpock
  • 24. 0.07 0.35 Test Density w/o RSpock with RSpock 400%improvement
  • 25. 20.3 54.5 Coverage avg. hits per line w/o RSpock avg. hits per line with RSpock 98%test coverage for both
  • 26. RSpock Code Blocks -> BDD Phases Code Block BDD Phase Given Setup When Stimulus Then Response Expect Stimulus + Response Cleanup Cleanup
  • 27. How Does it Work?
  • 29. Abstract Syntax Tree 1 + 2 int(1) send(:+) int(2) Ruby Code
  • 32. Given Given "An empty Cart and a Product" cart = Cart.new product = Product.new
  • 33. When When "Adding a product" cart.add_product(Product.new)
  • 34. Then Then "The product is added to the cart" cart.products.size == 1 cart.products.first == product
  • 35. Expect When "Calling #abs on a negative number" actual = -2.abs Then "Value is positive" actual == 2 Expect "absolute of -2 is 2" -2.abs == 2 Using Expect When + Then
  • 36. • Use When + Then to describe methods with side-effects • Use Expect to describe purely functional methods (query methods) Expect: Rule of Thumb
  • 37. Cleanup Given "Open the file" file = File.new("/invalid/file/path") # raises # other blocks... Cleanup # Use safe navigation operator, since +file+ is nil if an error occurred. file&.close
  • 38. Where test "#{a} XOR #{b} results in #{r}" do Expect a ^ b == r Where a | b | r 0 | 0 | 0 0 | 1 | 1 1 | 0 | 1 1 | 1 | 0 end
  • 40. • Describes ouputs in terms of possible inputs • Common approach in propositional logic and boolean algebra Truth Table
  • 41. Truth Table: XOR case in1 in2 out 1 0 0 0 2 0 1 1 3 1 0 1 4 1 1 0
  • 42. • Ordering test cases makes them easier to find and reason about. • Ordered data table makes it easier to understand test cases. • Recommend to order by boolean increment. Where Blocks
  • 43. Truth Table Generator $ rake rspock:truth_table -- a=-1,0,1 b=-1,0,1 r='?' a | b | r -1 | -1 | '?' -1 | 0 | '?' -1 | 1 | '?' 0 | -1 | '?' 0 | 0 | '?' 0 | 1 | '?' 1 | -1 | '?' 1 | 0 | '?' 1 | 1 | '?'
  • 44. Why do this? test "#{a} XOR #{b} results in #{r}" do Expect a ^ b == r Where a | b | r 0 | 0 | 0 0 | 1 | 1 1 | 0 | 1 1 | 1 | 0 end
  • 45. test "#{a} XOR #{b} results in #{r}" do Expect a ^ b == r Where a | b | r 0 | 0 | 0 0 | 1 | 1 1 | 0 | 1 1 | 1 | 0 end When you can do this: [ {a: 0, b: 0, r: 0}, {a: 0, b: 1, r: 1}, {a: 1, b: 0, r: 1}, {a: 1, b: 1, r: 1}, ].each do |a:, b:, r:| test "#{a} XOR #{b} results in #{r}" do assert_equal r, a ^ b end end Why do this?
  • 46. • Executed code != Source code • Debugging in Pry has slightly different code What’s the catch?
  • 47. • Better tooling support (i.e. Pry) • Open-sourcing the project • More features!! What’s next?
  • 48.
  • 49. • GitHub: https://github.com/rspockframework/rspock • RubyGems: https://rubygems.org/gems/rspock I’m In! How can I use it?