Slide 1

Slide 1 text

Bow Before MiniTest @adman65 - gh://twinturbo

Slide 2

Slide 2 text

MiniTest vs RSpec vs Test::Unit vs Cucumber

Slide 3

Slide 3 text

Forget Cucumber! • Long term cucumber use is detrimental to your brain • Makes you learn another syntax to write tests • Managing large test suites is painful • Small number of good use cases

Slide 4

Slide 4 text

MiniTest vs RSpec vs Test::Unit vs Cucumber

Slide 5

Slide 5 text

MiniTest & Test::Unit • Test::Unit is MiniTest in Ruby 1.9 • Test::Unit is a compatibility layer around MiniTest • This is for backward compatibility • We can forget about Test::Unit too...

Slide 6

Slide 6 text

MiniTest vs RSpec vs Test::Unit vs Cucumber

Slide 7

Slide 7 text

MiniTest vs RSpec

Slide 8

Slide 8 text

Kampf!

Slide 9

Slide 9 text

Things a Test Framework Should Do • Make it easy to write and maintain tests • Run tests in random order • Believe me, this will find bugs in your code • Make you focus on testing your code and not learning the framework yourself

Slide 10

Slide 10 text

Basics: Writing Tests

Slide 11

Slide 11 text

require 'minitest/autorun' class TruthTest < MiniTest::Unit::TestCase def test_truth assert true end end

Slide 12

Slide 12 text

require 'rspec' describe "Truth" do it "should be true" do true.should == true end end

Slide 13

Slide 13 text

Speed: Timing 10K Tests

Slide 14

Slide 14 text

require 'test_helper' class TruthTest < MiniTest::Unit::TestCase 10_000.times do |i| define_method "test_truth_#{i}" do assert true end end end

Slide 15

Slide 15 text

require 'spec_helper' describe "Truth" do 10_000.times do it { should_not be_nil } end end

Slide 16

Slide 16 text

Results # Tests MiniTest Rspec 1.000 0.069 0.428 10.000 0.730 3.92 100.000 8.345 39.53 Times in Seconds

Slide 17

Slide 17 text

Yes, this is Real :(

Slide 18

Slide 18 text

Analysis • MiniTest is clearly faster on tremendously large test suites • MiniTest is notably faster on smaller tests suites • RSpec will continue to slow down rapidly because matchers create objects which trigger garbage collection • Developers may notice a difference in typical test suites

Slide 19

Slide 19 text

Expressiveness: should vs assert

Slide 20

Slide 20 text

Rspec is testing DSL

Slide 21

Slide 21 text

describe Person do its(:phone_number) { should =~ /^\d+$/ } end

Slide 22

Slide 22 text

MiniTest is Ruby

Slide 23

Slide 23 text

class PersonTest < MiniTest::Unit::TestCase def test_phone_number_format person = Person.new assert_match person.phone_number, /^\d+$/ end end

Slide 24

Slide 24 text

Magic • RSpec: less code & more magic • MiniTest: more code & less magic

Slide 25

Slide 25 text

# 1. describe Person detects that the described # object is a class so `Person.new` is called # implicitly before each test and assigned to # `subject` describe Person do its(:phone_number) { should =~ /^\d+$/ } end

Slide 26

Slide 26 text

describe Person do # Call the `phone_number` method on subject # an assign it's return value to `subject` # inside the test block its(:phone_number) { should =~ /^\d+$/ } end

Slide 27

Slide 27 text

describe Person do # Call should on the implicit subject # so it can be tested against the regex its(:phone_number) { should =~ /^\d+$/ } end

Slide 28

Slide 28 text

I don’t like this complexity

Slide 29

Slide 29 text

Do I need to explain MiniTest?

Slide 30

Slide 30 text

Custom Matchers vs Custom Assertions

Slide 31

Slide 31 text

def assert_valid(model) assert model.valid?, "Expected #{model} to be valid" end

Slide 32

Slide 32 text

# There is a large API for this! # This is the most simple case RSpec::Matchers.define :be_valid do match do |model| model.valid? end end

Slide 33

Slide 33 text

Go read this file: https://github.com/rspec/ rspec-expectations/blob/master/lib/rspec/ matchers/built_in/base_matcher.rb

Slide 34

Slide 34 text

Writing custom assertions is easier and more understandable in MiniTest

Slide 35

Slide 35 text

def test_vendor_comes_before_app # do stuff to build a file content = read "site/application.js" assert_includes content, "APP" assert_includes content, "VENDOR" assert content.index("VENDOR") < content.index("APP"), "Vendor should come before App!" end

Slide 36

Slide 36 text

extract-method

Slide 37

Slide 37 text

def test_vendor_comes_before_app content = read "site/application.js" assert_before content, "VENDOR", "APP" end def assert_before(source, first, second) assert_includes content, first assert_includes content, second assert content.index(first) < content.index(source), "#{first} should be before #{second}" end

Slide 38

Slide 38 text

One Less Thing to Learn

Slide 39

Slide 39 text

You Don’t need to lookup a Matcher API, just write ruby methods

Slide 40

Slide 40 text

MiniTest will make your code better

Slide 41

Slide 41 text

Why? • Minimal feature set: focus on writing code • Removing a complex mocking/stubbing library makes you consider design • Run tests in random order--this will usually find bugs in your test suite or code • Can run your tests in parallel

Slide 42

Slide 42 text

class OrderDependentTest < MinitTest::Unit::TestCase i_suck_and_my_tests_are_order_dependent! def test_step1 # .... end def test_step2 # .... end end If you do in fact, suck at writing tests....

Slide 43

Slide 43 text

require 'minitest/unit' require 'minitest/hell' # put your tests through the ringer require 'minitest/autorun' class ParallelTests < MiniTest::Unit::TestCase def test_multi_threading # ... end end

Slide 44

Slide 44 text

tl;dr

Slide 45

Slide 45 text

Why MiniTest? • Its faster and lighter than Rspec • Its much easier to understand and extend • Random & parallel tests out of the box • Its part of the standard library so it’s available everywhere • More stable and better supported than Rspec • It will make your test suite better!

Slide 46

Slide 46 text

Why Rspec? • $ rspec foo_spec.rb • Running individual tests is trivially easy • You like DSL’s and complexity

Slide 47

Slide 47 text

die Slides http://speakerdeck.com/u/twinturbo