Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Lucas Mazza @lucasmazza http:/ /afterhours.io

Slide 3

Slide 3 text

https:/ /sp.femug.com https:/ /github.com/braziljs/femug

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Slide 6

Slide 6 text

Minitest Voltando ao básico sobre testes

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

https:/ /github.com/seattlerb/minitest

Slide 9

Slide 9 text

$ gem fetch minitest && gem unpack minitest-*.gem Downloaded minitest-5.9.0 Unpacked gem: '/private/tmp/minitest-5.9.0' $ cloc minitest-5.9.0/lib 14 text files. 14 unique files. 0 files ignored. github.com/AlDanial/cloc v 1.68 T=0.09 s (159.9 files/s, 38368.5 lines/s) ------------------------------------------------------------------------------- Language files blank comment code ------------------------------------------------------------------------------- Ruby 14 661 1072 1627 ------------------------------------------------------------------------------- SUM: 14 661 1072 1627 -------------------------------------------------------------------------------

Slide 10

Slide 10 text

Ruby arroz com feijão

Slide 11

Slide 11 text

class PostTest < Minitest::Test def test_sets_the_title post = Post.new post.title = 'The Post Title' assert_equal 'The Post Title', post.title end def test_publish_publishes_the_post post = Post.new post.publish! assert_predicate post, :published? end end

Slide 12

Slide 12 text

class PostTest < Minitest::Test def test_sets_the_title post = Post.new post.title = 'The Post Title' assert_equal 'The Post Title', post.title end def test_publish_publishes_the_post post = Post.new post.publish! assert_predicate post, :published? end end Caso de teste

Slide 13

Slide 13 text

class PostTest < Minitest::Test def test_sets_the_title post = Post.new post.title = 'The Post Title' assert_equal 'The Post Title', post.title end def test_publish_publishes_the_post post = Post.new post.publish! assert_predicate post, :published? end end Teste Teste Caso de teste

Slide 14

Slide 14 text

class PostTest < Minitest::Test def test_sets_the_title post = Post.new post.title = 'The Post Title' assert_equal 'The Post Title', post.title end def test_publish_publishes_the_post post = Post.new post.publish! assert_predicate post, :published? end end Teste Teste Asserção Asserção Caso de teste

Slide 15

Slide 15 text

RSpec.describe Post do it '#title= sets the title' do post = Post.new post.title = 'The Post Title' expect(post.title).to eq('The Post Title') end it '#publish! publishes the post' do post = Post.new post.publish! expect(post).to be_published end end Teste Teste Asserção Asserção Caso de teste

Slide 16

Slide 16 text

class PostSpec < RSpec::Core::ExampleGroup set_it_up 'Post', [], RSpec.world.example_groups RSpec::Core::Example.new(self, '#title= sets the title', {}, -> (example) { post = Post.new post.title = 'The Post Title' RSpec::Expectations::ExpectationTarget.new(post.title).to( RSpec::Matchers::BuiltIn::Eq.new('The Post Title')) }) RSpec::Core::Example.new(self, 'publish! publishes the post', {}, -> (example) { post = Post.new post.publish! RSpec::Expectations::ExpectationTarget.new(post).to( RSpec::Matchers::BuiltIn::BePredicate.new(:be_published)) }) end RSpec.world.record PostSpec

Slide 17

Slide 17 text

class PostSpec < RSpec::Core::ExampleGroup set_it_up 'Post', [], RSpec.world.example_groups RSpec::Core::Example.new(self, '#title= sets the title', {}, -> (example) { post = Post.new post.title = 'The Post Title' RSpec::Expectations::ExpectationTarget.new(post.title).to( RSpec::Matchers::BuiltIn::Eq.new('The Post Title')) }) RSpec::Core::Example.new(self, 'publish! publishes the post', {}, -> (example) { post = Post.new post.publish! RSpec::Expectations::ExpectationTarget.new(post).to( RSpec::Matchers::BuiltIn::BePredicate.new(:be_published)) }) end RSpec.world.record PostSpec Caso de teste

Slide 18

Slide 18 text

class PostSpec < RSpec::Core::ExampleGroup set_it_up 'Post', [], RSpec.world.example_groups RSpec::Core::Example.new(self, '#title= sets the title', {}, -> (example) { post = Post.new post.title = 'The Post Title' RSpec::Expectations::ExpectationTarget.new(post.title).to( RSpec::Matchers::BuiltIn::Eq.new('The Post Title')) }) RSpec::Core::Example.new(self, 'publish! publishes the post', {}, -> (example) { post = Post.new post.publish! RSpec::Expectations::ExpectationTarget.new(post).to( RSpec::Matchers::BuiltIn::BePredicate.new(:be_published)) }) end RSpec.world.record PostSpec Teste Teste Caso de teste

Slide 19

Slide 19 text

class PostSpec < RSpec::Core::ExampleGroup set_it_up 'Post', [], RSpec.world.example_groups RSpec::Core::Example.new(self, '#title= sets the title', {}, -> (example) { post = Post.new post.title = 'The Post Title' RSpec::Expectations::ExpectationTarget.new(post.title).to( RSpec::Matchers::BuiltIn::Eq.new('The Post Title')) }) RSpec::Core::Example.new(self, 'publish! publishes the post', {}, -> (example) { post = Post.new post.publish! RSpec::Expectations::ExpectationTarget.new(post).to( RSpec::Matchers::BuiltIn::BePredicate.new(:be_published)) }) end RSpec.world.record PostSpec Teste Teste Asserção Asserção Caso de teste

Slide 20

Slide 20 text

Acompanhamentos

Slide 21

Slide 21 text

class IntegrationTest < Minitest::Test def setup super DatabaseCleaner.start end def teardown super DatabaseCleaner.clean end end hooks

Slide 22

Slide 22 text

module SerializerTests def setup # ... end def test_serializer_works # ... end end Testes compartilhados

Slide 23

Slide 23 text

class JSONSerializerTest < MiniTest::Test include SerializerTests def serializer JSON end end class MarshalSerializerTest < MiniTest::Test include SerializerTests def serializer Marshal end end Testes compartilhados

Slide 24

Slide 24 text

# activerecord/test/cases/base_test.rb class LintTest < ActiveRecord::TestCase include ActiveModel::Lint::Tests class LintModel < ActiveRecord::Base; end def setup @model = LintModel.new end end Testes compartilhados

Slide 25

Slide 25 text

executando

Slide 26

Slide 26 text

$ command minitest -bash: minitest: command not found

Slide 27

Slide 27 text

require 'minitest/autorun' ruby test_file.rb ➕

Slide 28

Slide 28 text

class Post attr_accessor :title def publish! @published = true end def published? @published end end require 'minitest/autorun' class PostTest < Minitest::Test def test_sets_the_title post = Post.new post.title = 'The Post Title' assert_equal 'The Post Title', post.title end def test_publish_publishes_the_post post = Post.new post.publish! assert_predicate post, :published? end end

Slide 29

Slide 29 text

executando

Slide 30

Slide 30 text

# active_record_bug.rb require 'bundler/inline' gemfile(true) do source 'https://rubygems.org' gem 'activerecord', '5.0.0' gem 'sqlite3' end # ... executando

Slide 31

Slide 31 text

require 'active_record' require 'minitest/autorun' require 'logger' ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') ActiveRecord::Schema.define do create_table :posts, force: true do |t| end end class Post < ActiveRecord::Base end # ... executando

Slide 32

Slide 32 text

class BugTest < Minitest::Test def test_create_bang post = Post.create! assert_predicate post, :persisted? assert_equal 1, post.id end end executando

Slide 33

Slide 33 text

executando

Slide 34

Slide 34 text

http:/ /guides.rubyonrails.org/contributing_to_ruby_on_rails.html executando

Slide 35

Slide 35 text

asserções

Slide 36

Slide 36 text

assert assert_empty assert_equal assert_in_delta assert_in_epsilon assert_includes assert_instance_of assert_kind_of assert_match assert_nil assert_operator assert_output assert_predicate assert_raises assert_respond_to assert_same assert_send assert_silent assert_throws Minitest::Assertions

Slide 37

Slide 37 text

# lib/minitest/assertions.rb def assert_includes collection, obj, msg = nil msg = message(msg) { "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}" } assert_respond_to collection, :include? assert collection.include?(obj), msg end Minitest::Assertions

Slide 38

Slide 38 text

refute refute_empty refute_equal refute_in_delta refute_in_epsilon refute_includes refute_instance_of refute_kind_of refute_match refute_nil refute_operator refute_predicate refute_respond_to refute_same Minitest::Assertions

Slide 39

Slide 39 text

assert post.published? # Expected nil to be truthy. assert_predicate post, :published? # Expected # to be published?. Minitest::Assertions

Slide 40

Slide 40 text

# test/support/assertions.rb def refute_file(path, msg = nil) msg = message(msg) { "Expected '#{path}' to not exist." } refute File.exist?(path), msg end def assert_file(path, contents = nil, msg = nil) msg = message(msg) { "Expected '#{path}' to exist." } assert File.exist?(path), msg if contents.present? assert_equal contents, File.read(path) end end asserções

Slide 41

Slide 41 text

plugins

Slide 42

Slide 42 text

plugins minitest-around minitest-bisect minitest-capybara minitest-debugger minitest-proveit minitest-reporters minitest-utils minitest-matchers ...

Slide 43

Slide 43 text

fnando/minitest-utils require 'bundler/inline' gemfile(true) do gem 'minitest' gem 'minitest-utils', require: false end require 'minitest/autorun' class PluginTest < Minitest::Test def test_that_fails assert_equal 1, 2 end end

Slide 44

Slide 44 text

fnando/minitest-utils

Slide 45

Slide 45 text

fnando/minitest-utils

Slide 46

Slide 46 text

Minitest + Rails

Slide 47

Slide 47 text

require 'active_support' require 'active_support/test_case' class PostTest < ActiveSupport::TestCase test '#title= sets the title' do post = Post.new post.title = 'The Post Title' assert_equal 'The Post Title', post.title end test '#publish! publishes the post' do post = Post.new post.publish! assert_predicate post, :published? end end gem install activesupport

Slide 48

Slide 48 text

require 'active_support' require 'active_support/test_case' class PostTest < ActiveSupport::TestCase setup :setup_something setup { setup_something_else } teardown :teardown_something end gem install activesupport

Slide 49

Slide 49 text

assert_difference assert_deprecated assert_called assert_called_with assert_no_difference assert_not_deprecated assert_not assert_not_called gem install activesupport

Slide 50

Slide 50 text

Casos de teste ActionController::TestCase ActionDispatch::IntegrationTest ActionMailer::TestCase ActionView::TestCase ActiveJob::TestCase Módulos ActionMailer::TestHelper ActiveJob::TestHelper Minitest + Rails

Slide 51

Slide 51 text

Minitest + Rails

Slide 52

Slide 52 text

+ fixtures + travel_to + rails-controller-testing + ActionDispatch::PerformanceTest + ... Minitest + Rails

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

mocks & stubs

Slide 56

Slide 56 text

mocks book = double('book') null_book = double('book').as_null_object book = instance_double('Book', pages: 250) allow(book).to receive_messages( title: 'The RSpec Book', pages: 250) invitation = spy('invitation')

Slide 57

Slide 57 text

mocks require 'minitest/mock' book = Minitest::Mock.new book.expect(:pages, 250) book.expect(:title, 'The RSpec Book’) book.expect(:title, 'The RSpec Book’) book.expect(:update, true, [{ title: 'New Title’ }]) assert_mock book

Slide 58

Slide 58 text

stubs allow(book).to receive_messages( title: 'The RSpec Book', pages: 250) expect(book).to receive_messages( title: 'The RSpec Book', pages: 250) allow_any_instance_of(Book).to receive(:update).with(hash_including(title: 'New Title')) { true }

Slide 59

Slide 59 text

stubs Book.stub(:find, book) do book.stub(:update, true) do # ... end end

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

Mocks e stubs não são de graça

Slide 62

Slide 62 text

(E até que isso é bom)

Slide 63

Slide 63 text

“…any pain in faking something should be responded to not with ever-more-clever test double libraries, but with a redesign of the interaction between the subject and its dependencies.” Justin Searls - Don’t mock what you don’t own https:/ /github.com/testdouble/contributing-tests/wiki/Don't-mock-what-you-don't-own

Slide 64

Slide 64 text

+ API Design - Stubs

Slide 65

Slide 65 text

+ Fake objects - Mocks

Slide 66

Slide 66 text

+ Fake objects - Mocks Mockers without borders https:/ /github.com/testdouble/test-smells/blob/master/smells/unrealistic/mockers-without-borders.js

Slide 67

Slide 67 text

Escrita de testes

Slide 68

Slide 68 text

http:/ /blog.plataformatec.com.br/2014/04/improve-your-test-readability-using-the-xunit-structure/

Slide 69

Slide 69 text

RSpec.describe Post do subject { Post.new } let(:foo) { } let(:bar) { } describe '...' do before { } let(:bar) { } context '...' do before { } let(:foo) { } it { } it { } end context '...' do before { } let(:bar) { } it { } it { } it { } end end end

Slide 70

Slide 70 text

RSpec.describe Post do subject { Post.new } let(:foo) { } let(:bar) { } describe '...' do before { } let(:bar) { } context '...' do before { } let(:foo) { } it { } it { } end context '...' do before { } let(:bar) { } it { } it { } it { } end end end

Slide 71

Slide 71 text

RSpec.describe Post do subject { Post.new } let(:foo) { } let(:bar) { } describe '...' do before { } let(:bar) { } context '...' do before { } let(:foo) { } it { } it { } end context '...' do before { } let(:bar) { } it { } it { } it { } end end end

Slide 72

Slide 72 text

RSpec.describe Post do subject { Post.new } let(:foo) { } let(:bar) { } describe '...' do before { } let(:bar) { } context '...' do before { } let(:foo) { } it { } it { } end context '...' do before { } let(:bar) { } it { } it { } it { } end end end

Slide 73

Slide 73 text

RSpec.describe Post do subject { Post.new } let(:foo) { } let(:bar) { } describe '...' do before { } let(:bar) { } context '...' do before { } let(:foo) { } it { } it { } end context '...' do before { } let(:bar) { } it { } it { } it { } end end end (˽°□°҂˽Ɨ ˍ━ˍ

Slide 74

Slide 74 text

class PostTest < Minitest::Test def test_sets_the_title post = Post.new post.title = 'The Post Title' assert_equal 'The Post Title', post.title end end

Slide 75

Slide 75 text

class TestCase < Minitest::Test def test_name setup exercise verify end end

Slide 76

Slide 76 text

class TestCase < Minitest::Test def test_name verify end end

Slide 77

Slide 77 text

class TestCase < Minitest::Test def test_name verify end end

Slide 78

Slide 78 text

class TestCase < Minitest::Test def test_name verify end end ❓❓❓

Slide 79

Slide 79 text

+ Expressividade - DRY

Slide 80

Slide 80 text

+ Isolamento - Dependências

Slide 81

Slide 81 text

http:/ /xunitpatterns.com/index.html

Slide 82

Slide 82 text

Slide 83

Slide 83 text

class PostTest < Minitest::Test def test_sets_the_title post = Post.new post.title = 'The Post Title' assert_equal 'The Post Title', post.title end def test_publish_publishes_the_post post = Post.new post.publish! assert_predicate post, :published? end end

Slide 84

Slide 84 text

QUnit.module('Post tests'); QUnit.test('sets the post title', function(assert) { var post = new Post(); post.set('title', 'The Post Title'); assert.equal('The Post Title', post.get('title')); }); QUnit.test('post is publishable', function(assert) { var post = new Post(); post.publish(); assert.ok(post.isPublished()); });

Slide 85

Slide 85 text

defmodule PostTest do use ExUnit.Case test "sets the title" do post = %Post{} post = Map.put(post, :title, "The Post Title") assert "The Post Title" == post.title end test "publishes the post" do post = %Post{} post = Post.publish!(post) assert Post.published?(post) end end

Slide 86

Slide 86 text

RECAP!

Slide 87

Slide 87 text

Minitest é massa

Slide 88

Slide 88 text

(RSpec também :P)

Slide 89

Slide 89 text

Testar software vai além das nossas ferramentas

Slide 90

Slide 90 text

As vezes é bom revisitar o encontro da teoria e da prática

Slide 91

Slide 91 text

Obrigado! @lucasmazza https:/ /speakerdeck.com/lucas