├── 04-acceptance-specs
├── 04
│ ├── json_example.json
│ ├── json_example.irbr
│ ├── expense_tracker
│ │ ├── app
│ │ │ └── api.rb
│ │ └── spec
│ │ │ └── acceptance
│ │ │ └── expense_tracker_api_spec.rb
│ └── sessions
│ │ └── rspec_runs
│ │ ├── 2.pml
│ │ └── 1.pml
├── 06
│ ├── expense_tracker
│ │ ├── .gitignore
│ │ └── config.ru
│ └── sessions
│ │ ├── curl_output.pml
│ │ ├── boot_app.pml
│ │ └── rspec_runs
│ │ └── 1.pml
├── 02
│ ├── expense_tracker
│ │ ├── app
│ │ │ └── api.rb
│ │ └── spec
│ │ │ └── acceptance
│ │ │ └── expense_tracker_api_spec.rb
│ └── sessions
│ │ └── rspec_runs
│ │ ├── 2.pml
│ │ └── 1.pml
├── 03
│ ├── expense_tracker
│ │ ├── app
│ │ │ └── api.rb
│ │ └── spec
│ │ │ └── acceptance
│ │ │ └── expense_tracker_api_spec.rb
│ └── sessions
│ │ └── rspec_runs
│ │ ├── 2.pml
│ │ └── 1.pml
├── 01
│ ├── sessions
│ │ ├── initialize_rspec.pml
│ │ ├── initialize_bundler.pml
│ │ ├── rspec_runs
│ │ │ └── 1.pml
│ │ └── bundle_install.pml
│ └── expense_tracker
│ │ ├── Gemfile
│ │ └── spec
│ │ └── acceptance
│ │ └── expense_tracker_api_spec.rb
└── 05
│ ├── expense_tracker
│ └── app
│ │ └── api.rb
│ └── sessions
│ └── rspec_runs
│ ├── 1.pml
│ ├── 2.pml
│ ├── 3.pml
│ └── 4.pml
├── 00-introduction
├── 01
│ └── type_me_in.rb
├── 02
│ └── irb_session.irbr
└── 03
│ └── shell_example.pml
├── 01-getting-started
├── 01
│ ├── spec
│ │ └── sandwich_spec.rb
│ └── sessions
│ │ ├── check_rspec_version.pml
│ │ └── install_rspec.pml
├── 02
│ ├── spec
│ │ └── sandwich_spec.rb
│ ├── sandwich_test.rb
│ └── sessions
│ │ └── rspec_runs
│ │ └── 1.pml
├── 03
│ ├── spec
│ │ └── sandwich_spec.rb
│ └── sessions
│ │ └── rspec_runs
│ │ └── 1.pml
├── 04
│ ├── sessions
│ │ └── rspec_runs
│ │ │ └── 1.pml
│ └── spec
│ │ └── sandwich_spec.rb
├── 05
│ ├── sessions
│ │ └── rspec_runs
│ │ │ └── 1.pml
│ └── spec
│ │ └── sandwich_spec.rb
├── 07
│ ├── sessions
│ │ └── rspec_runs
│ │ │ └── 1.pml
│ └── spec
│ │ └── sandwich_spec.rb
├── 09
│ ├── sessions
│ │ └── rspec_runs
│ │ │ └── 1.pml
│ └── spec
│ │ └── sandwich_spec.rb
├── 08
│ └── toaster.rb
└── 06
│ ├── spec
│ └── sandwich_spec.rb
│ └── sessions
│ └── fail_toppings.pml
├── 06-integration-specs
├── 03
│ ├── expense_tracker
│ │ ├── config
│ │ │ └── sequel.rb
│ │ ├── spec
│ │ │ ├── support
│ │ │ │ └── db.rb
│ │ │ └── integration
│ │ │ │ └── app
│ │ │ │ └── ledger_spec.rb
│ │ └── db
│ │ │ └── migrations
│ │ │ └── 0001_create_expenses.rb
│ └── sessions
│ │ ├── sequel_migration.out.pml
│ │ └── rspec_runs
│ │ └── 1.pml
├── 07
│ ├── expense_tracker
│ │ └── spec
│ │ │ ├── integration
│ │ │ └── an_integration_spec.rb
│ │ │ └── support
│ │ │ └── db.rb
│ └── sessions
│ │ └── rspec_runs
│ │ ├── 3.pml
│ │ ├── 4.pml
│ │ ├── 5.pml
│ │ ├── 1.pml
│ │ └── 6.pml
├── 09
│ ├── sessions
│ │ ├── grep_config_sequel.pml
│ │ ├── curl_failure.pml
│ │ ├── rspec_runs
│ │ │ ├── 4.pml
│ │ │ ├── 2.pml
│ │ │ └── 3.pml
│ │ ├── curl_output_success.pml
│ │ ├── boot_app_success.pml
│ │ ├── server_failure.pml
│ │ ├── each_spec_file_failure.pml
│ │ └── each_spec_file_success.pml
│ └── expense_tracker
│ │ └── app
│ │ └── ledger.rb
├── 01
│ ├── expense_tracker
│ │ └── Gemfile
│ └── sessions
│ │ └── bundle_install.pml
├── 02
│ └── play_with_sequel.irbr
├── 06
│ ├── expense_tracker
│ │ └── app
│ │ │ └── ledger.rb
│ └── sessions
│ │ └── rspec_runs
│ │ └── 1.pml
├── 08
│ ├── sessions
│ │ └── rspec_runs
│ │ │ ├── 2.pml
│ │ │ └── 1.pml
│ └── expense_tracker
│ │ └── app
│ │ └── ledger.rb
├── 04
│ └── expense_tracker
│ │ └── spec
│ │ └── integration
│ │ └── app
│ │ └── ledger_spec.rb
└── 05
│ └── expense_tracker
│ └── spec
│ └── integration
│ └── app
│ └── ledger_spec.rb
├── 09-configuring-rspec
├── 02
│ ├── configuring_rspec
│ │ ├── .rspec
│ │ ├── spec
│ │ │ └── spec_helper.rb
│ │ ├── a_spec.rb
│ │ └── rspec
│ │ │ └── print_failures_eagerly.rb
│ └── sessions
│ │ ├── git_clone.pml
│ │ └── rspec_runs
│ │ └── 1.pml
├── 01
│ ├── configuring_rspec
│ │ └── spec
│ │ │ └── byebug_spec.rb
│ └── sessions
│ │ ├── require_byebug.pml
│ │ └── rspec_environment_options.txt.pml
├── exercises
│ └── fail_if_slower_than_spec.rb
├── 04
│ └── configuring_rspec
│ │ ├── rspec_mocks_configuration_spec.rb
│ │ ├── mocha_spec.rb
│ │ └── expect_with_spec.rb
└── 05
│ └── rspec_configure.rb
├── 12-creating-custom-matchers
├── 04
│ ├── example_user_hash.rb
│ └── sessions
│ │ └── rspec_runs
│ │ └── 1.pml
├── 06
│ ├── custom_matcher
│ │ ├── spec
│ │ │ ├── support
│ │ │ │ └── matchers.rb
│ │ │ └── initial_account_spec.rb
│ │ └── lib
│ │ │ └── account.rb
│ └── sessions
│ │ └── minimal_matcher_failure.pml
├── 01
│ ├── sessions
│ │ ├── better_failure_1.pml
│ │ ├── original_failure_1.pml
│ │ ├── original_failure_2.pml
│ │ └── better_failure_2.pml
│ └── custom_matcher
│ │ └── lib
│ │ └── event.rb
├── 07
│ ├── custom_matcher
│ │ └── spec
│ │ │ └── support
│ │ │ └── matchers.rb
│ └── sessions
│ │ └── improved_matcher_failure.pml
├── 02
│ └── sessions
│ │ └── rspec_runs
│ │ └── 1.pml
├── 03
│ └── sessions
│ │ └── rspec_runs
│ │ └── 1.pml
├── solutions
│ └── custom_matcher
│ │ └── spec
│ │ └── support
│ │ └── event_matchers.rb
├── 09
│ ├── sessions
│ │ └── composed_matcher_failure.pml
│ └── custom_matcher
│ │ └── spec
│ │ ├── composed_account_spec.rb
│ │ └── support
│ │ └── matchers.rb
├── 08
│ ├── sessions
│ │ └── as_of_matcher_failure.pml
│ └── custom_matcher
│ │ └── spec
│ │ ├── support
│ │ └── matchers.rb
│ │ └── as_of_account_spec.rb
├── 05
│ └── custom_matchers.irbr
└── exercises
│ └── custom_matcher
│ └── spec
│ └── event_matchers_spec.rb
├── 15-using-test-doubles-effectively
├── 10
│ └── api_request_tracker
│ │ ├── lib
│ │ ├── metrics_reporter.rb
│ │ ├── endpoint.rb
│ │ └── api_request_tracker.rb
│ │ └── spec
│ │ └── api_request_tracker_spec.rb
├── 11
│ └── api_request_tracker
│ │ └── spec
│ │ └── api_request_tracker_spec.rb
├── 12
│ └── api_request_tracker
│ │ ├── lib
│ │ ├── metrics_reporter.rb
│ │ └── api_request_tracker.rb
│ │ └── spec
│ │ └── api_request_tracker_spec.rb
├── 13
│ └── api_request_tracker
│ │ └── spec
│ │ └── api_request_tracker_spec.rb
├── 14
│ └── api_request_tracker
│ │ └── spec
│ │ └── api_request_tracker_spec.rb
├── 15
│ └── api_request_tracker
│ │ ├── lib
│ │ └── api_request_tracker.rb
│ │ └── spec
│ │ └── api_request_tracker_spec.rb
├── 16
│ └── api_request_tracker
│ │ ├── lib
│ │ └── api_request_tracker.rb
│ │ └── spec
│ │ └── api_request_tracker_spec.rb
├── 17
│ └── api_request_tracker
│ │ ├── lib
│ │ └── api_request_tracker.rb
│ │ └── spec
│ │ └── api_request_tracker_spec.rb
├── 18
│ └── twitter_user_formatter
│ │ ├── lib
│ │ └── twitter_user_formatter.rb
│ │ └── spec
│ │ ├── twitter_user_formatter_spec.rb
│ │ └── integration_spec.rb
├── 19
│ └── ruby_doc_server
│ │ ├── spec
│ │ └── ruby_doc_server_spec.rb
│ │ └── lib
│ │ └── ruby_doc_server.rb
├── 20
│ └── ruby_doc_server
│ │ └── spec
│ │ └── ruby_doc_server_spec.rb
├── 21
│ └── sales_tax
│ │ ├── Gemfile
│ │ └── lib
│ │ ├── invoice.rb
│ │ └── my_app.rb
├── 22
│ └── sales_tax
│ │ ├── spec
│ │ ├── integration
│ │ │ └── invoice_spec.rb
│ │ └── unit
│ │ │ └── invoice_spec.rb
│ │ └── lib
│ │ └── invoice.rb
├── 23
│ └── sales_tax
│ │ └── lib
│ │ └── sales_tax.rb
├── 24
│ └── sales_tax
│ │ ├── spec
│ │ ├── unit
│ │ │ └── invoice_spec.rb
│ │ └── integration
│ │ │ └── sales_tax_spec.rb
│ │ └── lib
│ │ └── invoice.rb
├── 04
│ └── daily_summary_email
│ │ ├── lib
│ │ ├── email_sender.rb
│ │ └── daily_summary.rb
│ │ └── spec
│ │ └── daily_summary_spec.rb
├── 01
│ ├── password_strength_validator
│ │ ├── lib
│ │ │ ├── configuration.rb
│ │ │ └── password_strength_validator.rb
│ │ └── spec
│ │ │ └── password_strength_validator_spec.rb
│ └── sessions
│ │ └── rspec_runs
│ │ └── 1.pml
├── 02
│ └── password_strength_validator
│ │ ├── lib
│ │ └── configuration.rb
│ │ └── spec
│ │ └── password_strength_validator_spec.rb
├── 06
│ └── subscription_service
│ │ ├── spec
│ │ ├── spec_helper.rb
│ │ └── recurring_payment_spec.rb
│ │ └── lib
│ │ ├── cash_cow.rb
│ │ └── recurring_payment.rb
├── 09
│ └── subscription_service
│ │ ├── spec
│ │ ├── spec_helper.rb
│ │ └── recurring_payment_spec.rb
│ │ └── lib
│ │ └── recurring_payment.rb
├── 08
│ └── subscription_service
│ │ └── lib
│ │ └── recurring_payment.rb
├── 03
│ └── daily_summary_email
│ │ ├── lib
│ │ └── daily_summary.rb
│ │ └── spec
│ │ └── daily_summary_spec.rb
├── 05
│ └── daily_summary_email
│ │ └── spec
│ │ └── daily_summary_spec.rb
├── 07
│ └── subscription_service
│ │ └── spec
│ │ └── recurring_payment_spec.rb
├── exercises
│ └── guessing_game
│ │ └── lib
│ │ └── guessing_game.rb
└── solutions
│ └── guessing_game
│ └── lib
│ └── guessing_game.rb
├── A2-using-rspec-with-rails
└── 01
│ ├── rails_app
│ └── spec
│ │ └── models
│ │ └── pterodactyl_spec.rb
│ └── sessions
│ ├── reinstall_binstubs.pml
│ ├── install_rspec.pml
│ └── generate_pterodactyl.pml
├── 08-metadata
├── 10
│ └── spec
│ │ └── music_storage_spec.rb
├── 11
│ └── spec
│ │ └── spec_helper.rb
├── 12
│ └── spec
│ │ └── spec_helper.rb
├── 13
│ └── random_order.rb
├── 05
│ └── spec
│ │ ├── spec_helper.rb
│ │ ├── unit
│ │ └── unit_spec.rb
│ │ └── integration
│ │ └── integration_spec.rb
├── 01
│ ├── spec
│ │ └── metadata_spec.rb
│ └── sessions
│ │ └── rspec_runs
│ │ └── 1.pml
├── 08
│ └── spec
│ │ ├── metadata_spec.rb
│ │ ├── spec_helper.rb
│ │ └── aggregate_failures_spec.rb
├── 03
│ └── spec
│ │ └── metadata_spec.rb
├── 09
│ └── around_hook.rb
├── 02
│ └── spec
│ │ └── metadata_spec.rb
├── 04
│ └── spec
│ │ ├── metadata_spec.rb
│ │ └── metadata_inheritance_spec.rb
├── 06
│ └── spec
│ │ └── spec_helper.rb
├── 07
│ └── aggregate_failures.rb
└── exercises
│ └── expense_tracker
│ └── spec
│ └── support
│ └── db.rb
├── 05-unit-specs
├── 10
│ ├── expense_tracker
│ │ └── app
│ │ │ └── ledger.rb
│ └── sessions
│ │ └── rspec_runs
│ │ └── 1.pml
├── 11
│ └── expense_tracker
│ │ └── spec
│ │ └── unit
│ │ └── api_example_spec.rb
├── 12
│ ├── expense_tracker
│ │ └── app
│ │ │ ├── ledger.rb
│ │ │ └── api.rb
│ └── sessions
│ │ └── rspec_runs
│ │ └── 3.pml
├── 08
│ └── expense_tracker
│ │ └── app
│ │ ├── ledger.rb
│ │ └── api.rb
├── 09
│ └── expense_tracker
│ │ └── app
│ │ └── ledger.rb
├── 03
│ ├── sessions
│ │ └── rspec_runs
│ │ │ ├── 2.pml
│ │ │ └── 1.pml
│ └── expense_tracker
│ │ ├── app
│ │ └── api.rb
│ │ ├── api_snippets.rb
│ │ └── spec
│ │ └── unit
│ │ └── app
│ │ └── api_spec.rb
├── 04
│ ├── expense_tracker
│ │ └── app
│ │ │ └── api.rb
│ └── sessions
│ │ └── rspec_runs
│ │ ├── 1.pml
│ │ └── 2.pml
├── 02
│ ├── expense_tracker
│ │ └── spec
│ │ │ └── unit
│ │ │ └── app
│ │ │ └── api_spec.rb
│ └── sessions
│ │ └── rspec_runs
│ │ └── 1.pml
└── 07
│ ├── expense_tracker
│ └── app
│ │ └── api.rb
│ └── sessions
│ └── rspec_runs
│ └── 1.pml
├── A1-rspec-and-wider-ecosystem
├── 02
│ ├── sessions
│ │ ├── rake_spec.pml
│ │ └── rake_doc_format.pml
│ └── expense_tracker
│ │ └── Rakefile
├── 01
│ └── sessions
│ │ ├── bundle_install_standalone.pml
│ │ ├── bundle_install_standalone_binstubs.pml
│ │ ├── each_spec_bin_rspec.pml
│ │ └── each_spec_bundle_exec.pml
└── 03
│ └── minitest_with_rspec
│ └── dinosaur_test.rb
├── 13-understanding-test-doubles
├── exercises
│ ├── mountain
│ │ ├── spec
│ │ │ ├── support
│ │ │ │ └── verify_doubled_constants.rb
│ │ │ └── skier_spec.rb
│ │ └── lib
│ │ │ ├── trail_map.rb
│ │ │ └── skier.rb
│ └── sessions
│ │ └── rspec_runs
│ │ ├── 1.pml
│ │ ├── 2.pml
│ │ └── 3.pml
├── 03
│ └── stubbed_constants.rb
└── 02
│ └── expense_tracker
│ ├── spec
│ └── unit
│ │ └── ledger_double_spec.rb
│ └── app
│ └── api.rb
├── 10-exploring-rspec-expectations
├── 02
│ ├── should_example.rb
│ ├── parts_of_an_expectation.rb
│ └── good_failure_messages.rb
├── 01
│ └── expectation_examples.rb
├── 06
│ ├── spec
│ │ ├── cookie_recipe_should_spec.rb
│ │ ├── cookie_recipe_subject_spec.rb
│ │ ├── cookie_recipe_no_doc_strings_spec.rb
│ │ └── cookie_recipe_spec.rb
│ └── sessions
│ │ └── rspec_runs
│ │ ├── 1.pml
│ │ ├── 3.pml
│ │ ├── 4.pml
│ │ └── 2.pml
├── 05
│ └── generated_example_descriptions.irbr
├── 03
│ └── how_matchers_work.irbr
└── 04
│ └── composing_matchers.rb
├── 07-structuring-code-examples
├── 10
│ └── shared_examples
│ │ ├── lib
│ │ └── hash_kv_store.rb
│ │ └── spec
│ │ └── hash_kv_store_spec.rb
├── 11
│ ├── shared_examples
│ │ ├── spec
│ │ │ ├── hash_kv_store_spec.rb
│ │ │ ├── include_examples_spec.rb
│ │ │ ├── it_behaves_like_twice_spec.rb
│ │ │ ├── include_examples_twice_spec.rb
│ │ │ ├── support
│ │ │ │ └── kv_store_shared_examples.rb
│ │ │ └── pass_block_spec.rb
│ │ └── lib
│ │ │ └── file_kv_store.rb
│ └── sessions
│ │ └── rspec_runs
│ │ ├── 2.pml
│ │ ├── 1.pml
│ │ ├── 5.pml
│ │ ├── 3.pml
│ │ └── 4.pml
├── 04
│ ├── config_hooks_spec.rb
│ ├── around_hooks_spec.rb
│ ├── spec
│ │ └── spec_helper.rb
│ └── before_and_after_hooks_spec.rb
├── 05
│ └── expense_tracker
│ │ └── spec
│ │ └── support
│ │ └── db.rb
├── 02
│ └── expense_tracker
│ │ └── Gemfile
├── 06
│ └── transit
│ │ ├── lib
│ │ └── berlin_transit_ticket.rb
│ │ └── spec
│ │ ├── berlin_transit_ticket_refactored_spec.rb
│ │ └── berlin_transit_ticket_spec.rb
├── solutions
│ └── shared_examples_exercise
│ │ └── spec
│ │ ├── uri_spec.rb
│ │ ├── addressable_spec.rb
│ │ └── support
│ │ └── shared_examples.rb
├── exercises
│ └── shared_examples_exercise
│ │ └── spec
│ │ ├── uri_spec.rb
│ │ └── addressable_spec.rb
└── 03
│ └── expense_tracker
│ └── spec
│ └── api_spec.rb
├── 02-running-specs
├── 10
│ └── spec
│ │ └── coffee_spec.rb
├── 11
│ ├── sessions
│ │ └── rspec_runs
│ │ │ └── 1.pml
│ └── spec
│ │ └── coffee_spec.rb
├── 02
│ └── sessions
│ │ ├── install_coderay.pml
│ │ └── rspec_runs
│ │ └── 1.pml
├── 03
│ ├── spec
│ │ └── slow_spec.rb
│ └── sessions
│ │ └── rspec_runs
│ │ └── 1.pml
├── 06
│ ├── sessions
│ │ └── rspec_runs
│ │ │ ├── 1.pml
│ │ │ ├── 5.pml
│ │ │ ├── 6.pml
│ │ │ ├── 2.pml
│ │ │ ├── 3.pml
│ │ │ └── 4.pml
│ └── spec
│ │ └── coffee_spec.rb
├── 07
│ ├── sessions
│ │ └── rspec_runs
│ │ │ └── 1.pml
│ └── spec
│ │ └── coffee_spec.rb
├── 08
│ ├── sessions
│ │ └── rspec_runs
│ │ │ └── 1.pml
│ └── spec
│ │ └── coffee_spec.rb
├── exercises
│ └── spec
│ │ └── tea_spec.rb
├── 05
│ └── sessions
│ │ └── rspec_runs
│ │ ├── 1.pml
│ │ └── 2.pml
├── solutions
│ ├── 01
│ │ └── spec
│ │ │ └── tea_spec.rb
│ └── 02
│ │ └── spec
│ │ └── tea_spec.rb
├── 01
│ ├── spec
│ │ └── coffee_spec.rb
│ └── sessions
│ │ └── rspec_runs
│ │ ├── 1.pml
│ │ └── 2.pml
├── 09
│ ├── sessions
│ │ └── rspec_runs
│ │ │ └── 1.pml
│ └── spec
│ │ └── coffee_spec.rb
└── 04
│ └── sessions
│ └── rspec_runs
│ └── 1.pml
├── 11-matchers-included-in-rspec-expectations
├── exercises
│ ├── water_spec.rb
│ ├── calendar_spec.rb
│ ├── tokenizer_spec.rb
│ ├── phone_number_extractor_spec.rb
│ ├── sessions
│ │ ├── calendar_spec.pml
│ │ ├── water_spec.pml
│ │ └── phone_number_extractor_spec.pml
│ └── public_company_spec.rb
└── solutions
│ ├── water_spec.rb
│ ├── calendar_spec.rb
│ ├── tokenizer_spec.rb
│ ├── phone_number_extractor_spec.rb
│ ├── sessions
│ ├── calendar_spec.pml
│ ├── water_spec.pml
│ └── tokenizer_spec.pml
│ └── public_company_spec.rb
├── A3-matcher-cheat-sheet
└── 01
│ └── matchers_cheat_sheet.rb
└── 14-customizing-test-doubles
├── 01
└── and_return.irbr
└── 02
└── stock_ticker.rb
/04-acceptance-specs/04/json_example.json:
--------------------------------------------------------------------------------
1 | { "expense_id": 42 }
2 |
--------------------------------------------------------------------------------
/00-introduction/01/type_me_in.rb:
--------------------------------------------------------------------------------
1 | puts "You can type me in; it's okay!"
2 |
--------------------------------------------------------------------------------
/04-acceptance-specs/06/expense_tracker/.gitignore:
--------------------------------------------------------------------------------
1 | spec/examples.txt
2 | db/*.db
3 | bin
4 | bundle
5 | log
6 |
--------------------------------------------------------------------------------
/04-acceptance-specs/06/expense_tracker/config.ru:
--------------------------------------------------------------------------------
1 | require_relative 'app/api'
2 | run ExpenseTracker::API.new
3 |
--------------------------------------------------------------------------------
/01-getting-started/01/spec/sandwich_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | RSpec.describe 'An ideal sandwich' do
3 | it 'is delicious' do
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/00-introduction/02/irb_session.irbr:
--------------------------------------------------------------------------------
1 | >> %w[Type in just the bit after the prompt].join(' ')
2 | => "Type in just the bit after the prompt"
3 |
--------------------------------------------------------------------------------
/04-acceptance-specs/04/json_example.irbr:
--------------------------------------------------------------------------------
1 | >> require 'json'
2 | => true
3 | >> JSON.parse('{ "expense_id": 42 }')
4 | => {"expense_id"=>42}
5 |
--------------------------------------------------------------------------------
/06-integration-specs/03/expense_tracker/config/sequel.rb:
--------------------------------------------------------------------------------
1 | require 'sequel'
2 | DB = Sequel.sqlite("./db/#{ENV.fetch('RACK_ENV', 'development')}.db")
3 |
--------------------------------------------------------------------------------
/09-configuring-rspec/02/configuring_rspec/.rspec:
--------------------------------------------------------------------------------
1 | -I<%= ENV['HOME'] %>/rspec-print_failures_eagerly/lib
2 | --require 'rspec/print_failures_eagerly'
3 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/04/example_user_hash.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 |
3 | {
4 | id: 1,
5 | email: 'john.doe@example.com',
6 | role: 'admin'
7 | }
8 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/10/api_request_tracker/lib/metrics_reporter.rb:
--------------------------------------------------------------------------------
1 | class MetricsReporter
2 | def increment(metric_name)
3 | # ...
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/A2-using-rspec-with-rails/01/rails_app/spec/models/pterodactyl_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Pterodactyl, type: :model do
4 | # ...
5 | end
6 |
--------------------------------------------------------------------------------
/04-acceptance-specs/02/expense_tracker/app/api.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 |
4 | module ExpenseTracker
5 | class API < Sinatra::Base
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/12/api_request_tracker/lib/metrics_reporter.rb:
--------------------------------------------------------------------------------
1 | class MetricsReporter
2 | def self.increment(metric_name)
3 | # ...
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/08-metadata/05/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.define_derived_metadata(file_path: /spec\/unit/) do |meta|
3 | meta[:fast] = true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/05-unit-specs/08/expense_tracker/app/ledger.rb:
--------------------------------------------------------------------------------
1 | module ExpenseTracker
2 | RecordResult = Struct.new(:success?, :expense_id, :error_message)
3 |
4 | class Ledger
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/08-metadata/01/spec/metadata_spec.rb:
--------------------------------------------------------------------------------
1 | require 'pp'
2 |
3 | RSpec.describe Hash do
4 | it 'is used by RSpec for metadata' do |example|
5 | pp example.metadata
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/08-metadata/08/spec/metadata_spec.rb:
--------------------------------------------------------------------------------
1 | require 'pp'
2 |
3 | RSpec.describe Hash do
4 | it 'is used by RSpec for metadata' do |example|
5 | pp example.metadata
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/06-integration-specs/07/expense_tracker/spec/integration/an_integration_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative '../support/db'
2 |
3 | RSpec.describe 'An integration spec', :db do
4 | # ...
5 | end
6 |
--------------------------------------------------------------------------------
/08-metadata/03/spec/metadata_spec.rb:
--------------------------------------------------------------------------------
1 | require 'pp'
2 |
3 | RSpec.describe Hash do
4 | it 'is used by RSpec for metadata', :fast do |example|
5 | pp example.metadata
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/08-metadata/09/around_hook.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'rspec'
3 |
4 | RSpec.configure do |config|
5 | config.around(:example) do |example|
6 | pp example.metadata
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/09-configuring-rspec/01/configuring_rspec/spec/byebug_spec.rb:
--------------------------------------------------------------------------------
1 | RSpec.describe 'Byebug' do
2 | it 'can use the debugger' do
3 | expect(self).to respond_to(:debugger)
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/08-metadata/02/spec/metadata_spec.rb:
--------------------------------------------------------------------------------
1 | require 'pp'
2 |
3 | RSpec.describe Hash do
4 | it 'is used by RSpec for metadata', fast: true do |example|
5 | pp example.metadata
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/08-metadata/05/spec/unit/unit_spec.rb:
--------------------------------------------------------------------------------
1 | RSpec.describe 'A unit spec' do
2 | it 'gets `fast: true` metadata' do |example|
3 | expect(example.metadata).to include(fast: true)
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/06/custom_matcher/spec/support/matchers.rb:
--------------------------------------------------------------------------------
1 | RSpec::Matchers.define :have_a_balance_of do |amount|
2 | match { |account| account.current_balance == amount }
3 | end
4 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/04/daily_summary_email/lib/email_sender.rb:
--------------------------------------------------------------------------------
1 | class EmailSender
2 | def deliver(email:, subject:, body:)
3 | # send the message via SMTP
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/08-metadata/04/spec/metadata_spec.rb:
--------------------------------------------------------------------------------
1 | require 'pp'
2 |
3 | RSpec.describe Hash do
4 | it 'is used by RSpec for metadata', :fast, :focus do |example|
5 | pp example.metadata
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/01/password_strength_validator/lib/configuration.rb:
--------------------------------------------------------------------------------
1 | module Acme
2 | module Config
3 | def self.min_password_length
4 | 12
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/02/password_strength_validator/lib/configuration.rb:
--------------------------------------------------------------------------------
1 | module Acme
2 | module Config
3 | def self.min_password_length
4 | 12
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/08-metadata/13/random_order.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'rspec'
3 |
4 | class SomeNewExampleGroup
5 | end
6 |
7 | RSpec.describe SomeNewExampleGroup, order: :random do
8 | # ...
9 | end
10 |
--------------------------------------------------------------------------------
/08-metadata/08/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.define_derived_metadata do |meta|
3 | meta[:aggregate_failures] = true unless meta.key?(:aggregate_failures)
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/06/subscription_service/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.mock_with :rspec do |mocks|
3 | mocks.verify_partial_doubles = true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/09/subscription_service/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.mock_with :rspec do |mocks|
3 | mocks.verify_partial_doubles = true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/A1-rspec-and-wider-ecosystem/02/sessions/rake_spec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rake spec
5 |
6 |
--------------------------------------------------------------------------------
/05-unit-specs/09/expense_tracker/app/ledger.rb:
--------------------------------------------------------------------------------
1 | module ExpenseTracker
2 | RecordResult = Struct.new(:success?, :expense_id, :error_message)
3 |
4 | class Ledger
5 | def record
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/09-configuring-rspec/01/sessions/require_byebug.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec -rbyebug
5 |
6 |
--------------------------------------------------------------------------------
/13-understanding-test-doubles/exercises/mountain/spec/support/verify_doubled_constants.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |c|
2 | c.mock_with :rspec do |mocks|
3 | mocks.verify_doubled_constant_names = true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/13-understanding-test-doubles/exercises/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 |
6 |
--------------------------------------------------------------------------------
/00-introduction/03/shell_example.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ echo 'RSpec is great!'
5 | RSpec is great!
6 |
7 |
--------------------------------------------------------------------------------
/04-acceptance-specs/03/expense_tracker/app/api.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 |
4 | module ExpenseTracker
5 | class API < Sinatra::Base
6 | post '/expenses' do
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/02/should_example.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'rspec/expectations'
3 | include RSpec::Matchers
4 |
5 | RSpec::Expectations.configuration.syntax = :should
6 |
7 | 'food'.should match(/foo/)
8 |
--------------------------------------------------------------------------------
/08-metadata/05/spec/integration/integration_spec.rb:
--------------------------------------------------------------------------------
1 | RSpec.describe 'An integration spec' do
2 | it 'does not get `fast: true` metadata' do |example|
3 | expect(example.metadata).not_to include(fast: true)
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/09-configuring-rspec/exercises/fail_if_slower_than_spec.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'rspec/core'
3 |
4 | SomeFastUnitSpecs = Class.new
5 |
6 | RSpec.describe SomeFastUnitSpecs, fail_if_slower_than: 0.01 do
7 | # ...
8 | end
9 |
--------------------------------------------------------------------------------
/13-understanding-test-doubles/exercises/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec -rtrail_map
5 |
6 |
--------------------------------------------------------------------------------
/05-unit-specs/10/expense_tracker/app/ledger.rb:
--------------------------------------------------------------------------------
1 | module ExpenseTracker
2 | RecordResult = Struct.new(:success?, :expense_id, :error_message)
3 |
4 | class Ledger
5 | def record(expense)
6 | end
7 |
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/shared_examples/spec/hash_kv_store_spec.rb:
--------------------------------------------------------------------------------
1 | require 'hash_kv_store'
2 | require 'support/kv_store_shared_examples'
3 |
4 | RSpec.describe HashKVStore do
5 | it_behaves_like 'KV store', HashKVStore
6 | end
7 |
--------------------------------------------------------------------------------
/A1-rspec-and-wider-ecosystem/02/sessions/rake_doc_format.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rake spec:unit SPEC_OPTS='-fd'
5 |
6 |
--------------------------------------------------------------------------------
/06-integration-specs/03/expense_tracker/spec/support/db.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |c|
2 | c.before(:suite) do
3 | Sequel.extension :migration
4 | Sequel::Migrator.run(DB, 'db/migrations')
5 | DB[:expenses].truncate
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/shared_examples/spec/include_examples_spec.rb:
--------------------------------------------------------------------------------
1 | require 'hash_kv_store'
2 | require 'support/kv_store_shared_examples'
3 |
4 | RSpec.describe HashKVStore do
5 | include_examples 'KV store', HashKVStore
6 | end
7 |
--------------------------------------------------------------------------------
/A1-rspec-and-wider-ecosystem/01/sessions/bundle_install_standalone.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle install --standalone
5 |
6 |
--------------------------------------------------------------------------------
/04-acceptance-specs/06/sessions/curl_output.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ curl localhost:9292/expenses/2017-06-10 -w "\n"
5 | []
6 |
7 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/10/api_request_tracker/lib/endpoint.rb:
--------------------------------------------------------------------------------
1 | Request = Struct.new(:verb, :path)
2 |
3 | class Endpoint
4 | def self.description_of(request)
5 | "#{request.verb}_#{request.path.sub(%r{^/}, '')}"
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/09-configuring-rspec/04/configuring_rspec/rspec_mocks_configuration_spec.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.mock_with :rspec do |mocks|
3 | mocks.verify_partial_doubles = true
4 | mocks.verify_doubled_constant_names = true
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/A2-using-rspec-with-rails/01/sessions/reinstall_binstubs.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle config --delete bin
5 | $ rails app:update:bin
6 |
7 |
--------------------------------------------------------------------------------
/13-understanding-test-doubles/exercises/sessions/rspec_runs/3.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec -rtrail_map -rsupport/verify_doubled_constants
5 |
6 |
--------------------------------------------------------------------------------
/A1-rspec-and-wider-ecosystem/01/sessions/bundle_install_standalone_binstubs.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle install --standalone --binstubs
5 |
6 |
--------------------------------------------------------------------------------
/04-acceptance-specs/04/expense_tracker/app/api.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 |
4 | module ExpenseTracker
5 | class API < Sinatra::Base
6 | post '/expenses' do
7 | JSON.generate('expense_id' => 42)
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/09-configuring-rspec/02/configuring_rspec/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | class MyFormatter
2 | RSpec::Core::Formatters.register self
3 |
4 | def initialize(_)
5 | end
6 | end
7 |
8 | RSpec.configure do |config|
9 | config.add_formatter MyFormatter
10 | end
11 |
--------------------------------------------------------------------------------
/09-configuring-rspec/02/sessions/git_clone.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ git clone https://github.com/rspec-3-book/rspec-print_failures_eagerly.git
5 |
6 |
--------------------------------------------------------------------------------
/01-getting-started/02/spec/sandwich_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | RSpec.describe 'An ideal sandwich' do
3 | it 'is delicious' do
4 | sandwich = Sandwich.new('delicious', [])
5 |
6 | taste = sandwich.taste
7 |
8 | expect(taste).to eq('delicious')
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/04-acceptance-specs/01/sessions/initialize_rspec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec --init
5 | create .rspec
6 | create spec/spec_helper.rb
7 |
8 |
--------------------------------------------------------------------------------
/02-running-specs/02/sessions/install_coderay.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ gem install coderay -v 1.1.1
5 | Successfully installed coderay-1.1.1
6 | 1 gem installed
7 |
8 |
--------------------------------------------------------------------------------
/05-unit-specs/12/expense_tracker/app/ledger.rb:
--------------------------------------------------------------------------------
1 | module ExpenseTracker
2 | RecordResult = Struct.new(:success?, :expense_id, :error_message)
3 |
4 | class Ledger
5 | def record(expense)
6 | end
7 |
8 | def expenses_on(date)
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/06-integration-specs/03/expense_tracker/db/migrations/0001_create_expenses.rb:
--------------------------------------------------------------------------------
1 | Sequel.migration do
2 | change do
3 | create_table :expenses do
4 | primary_key :id
5 | String :payee
6 | Float :amount
7 | Date :date
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/10/shared_examples/lib/hash_kv_store.rb:
--------------------------------------------------------------------------------
1 | class HashKVStore
2 | def initialize
3 | @hash = {}
4 | end
5 |
6 | def store(key, value)
7 | @hash[key] = value
8 | end
9 |
10 | def fetch(key)
11 | @hash.fetch(key)
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/13-understanding-test-doubles/exercises/mountain/lib/trail_map.rb:
--------------------------------------------------------------------------------
1 | puts 'Loading our database query library...'
2 | sleep(1)
3 |
4 | module Mountain
5 | class TrailMap
6 | def difficulty_of(trail_name)
7 | # Look up the trail in the database
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/01/sessions/better_failure_1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | [31m expected # to have no tickets sold, but ↩
5 | had 2[0m
6 |
7 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/01/sessions/original_failure_1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | [31m expected: 0[0m
5 | [31m got: 2[0m
6 | [31m[0m
7 | [31m (compared using ==)[0m
8 |
9 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/18/twitter_user_formatter/lib/twitter_user_formatter.rb:
--------------------------------------------------------------------------------
1 | require 'twitter'
2 |
3 | class TwitterUserFormatter
4 | def initialize(user)
5 | @user = user
6 | end
7 |
8 | def format
9 | @user.name + "'s website is " + @user.url
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/exercises/water_spec.rb:
--------------------------------------------------------------------------------
1 | class Water
2 | def self.elements
3 | [:oxygen, :hydrogen]
4 | end
5 | end
6 |
7 | RSpec.describe Water do
8 | it 'is H2O' do
9 | expect(Water.elements.sort).to eq [:hydrogen, :hydrogen, :oxygen]
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/solutions/water_spec.rb:
--------------------------------------------------------------------------------
1 | class Water
2 | def self.elements
3 | [:oxygen, :hydrogen]
4 | end
5 | end
6 |
7 | RSpec.describe Water do
8 | it 'is H2O' do
9 | expect(Water.elements).to contain_exactly(:hydrogen, :hydrogen, :oxygen)
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/01/sessions/original_failure_2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | [31m expected: 10000[0m
5 | [31m got: 9900[0m
6 | [31m[0m
7 | [31m (compared using ==)[0m
8 |
9 |
--------------------------------------------------------------------------------
/01-getting-started/03/spec/sandwich_spec.rb:
--------------------------------------------------------------------------------
1 | Sandwich = Struct.new(:taste, :toppings)
2 |
3 | RSpec.describe 'An ideal sandwich' do
4 | it 'is delicious' do
5 | sandwich = Sandwich.new('delicious', [])
6 |
7 | taste = sandwich.taste
8 |
9 | expect(taste).to eq('delicious')
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/04-acceptance-specs/01/expense_tracker/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | source "https://rubygems.org"
3 |
4 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
5 |
6 | gem 'rspec', '3.6.0'
7 | gem 'coderay', '1.1.1'
8 | gem 'rack-test', '0.7.0'
9 | gem 'sinatra', '2.0.0'
10 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/01/sessions/better_failure_2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | [31m expected # to be sold out, but had ↩
5 | 100 unsold tickets[0m
6 |
7 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/shared_examples/spec/it_behaves_like_twice_spec.rb:
--------------------------------------------------------------------------------
1 | require 'hash_kv_store'
2 | require 'file_kv_store'
3 | require 'support/kv_store_shared_examples'
4 |
5 | RSpec.describe 'Key-value stores' do
6 | it_behaves_like 'KV store', HashKVStore
7 | it_behaves_like 'KV store', FileKVStore
8 | end
9 |
--------------------------------------------------------------------------------
/01-getting-started/03/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m
6 |
7 | Finished in 0.00101 seconds (files took 0.08408 seconds to load)
8 | [32m1 example, 0 failures[0m
9 |
10 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/shared_examples/spec/include_examples_twice_spec.rb:
--------------------------------------------------------------------------------
1 | require 'hash_kv_store'
2 | require 'file_kv_store'
3 | require 'support/kv_store_shared_examples'
4 |
5 | RSpec.describe 'Key-value stores' do
6 | include_examples 'KV store', HashKVStore
7 | include_examples 'KV store', FileKVStore
8 | end
9 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/02/parts_of_an_expectation.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'rspec/expectations'
3 | include RSpec::Matchers
4 |
5 | class Deck
6 | def cards
7 | @cards ||= Array.new(52)
8 | end
9 | end
10 |
11 | deck = Deck.new
12 | expect(deck.cards.count).to eq(52), 'not playing with a full deck'
13 |
--------------------------------------------------------------------------------
/02-running-specs/03/spec/slow_spec.rb:
--------------------------------------------------------------------------------
1 | RSpec.describe 'The sleep() method' do
2 | it('can sleep for 0.1 second') { sleep 0.1 }
3 | it('can sleep for 0.2 second') { sleep 0.2 }
4 | it('can sleep for 0.3 second') { sleep 0.3 }
5 | it('can sleep for 0.4 second') { sleep 0.4 }
6 | it('can sleep for 0.5 second') { sleep 0.5 }
7 | end
8 |
--------------------------------------------------------------------------------
/06-integration-specs/09/sessions/grep_config_sequel.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ grep config/sequel -r . --exclude-dir=.git
5 | ./spec/integration/app/ledger_spec.rb:require_relative '../../../config ↩
6 | /sequel'
7 |
8 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/21/sales_tax/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | source "https://rubygems.org"
3 |
4 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
5 |
6 | gem 'rspec', '3.6.0'
7 | gem 'coderay', '1.1.1'
8 | gem 'taxjar-ruby', '1.7.0'
9 | gem 'dotenv', '2.2.1'
10 |
--------------------------------------------------------------------------------
/01-getting-started/04/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m[32m.[0m
6 |
7 | Finished in 0.00201 seconds (files took 0.09252 seconds to load)
8 | [32m2 examples, 0 failures[0m
9 |
10 |
--------------------------------------------------------------------------------
/01-getting-started/05/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m[32m.[0m
6 |
7 | Finished in 0.00206 seconds (files took 0.08537 seconds to load)
8 | [32m2 examples, 0 failures[0m
9 |
10 |
--------------------------------------------------------------------------------
/01-getting-started/07/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m[32m.[0m
6 |
7 | Finished in 0.00191 seconds (files took 0.08132 seconds to load)
8 | [32m2 examples, 0 failures[0m
9 |
10 |
--------------------------------------------------------------------------------
/01-getting-started/09/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m[32m.[0m
6 |
7 | Finished in 0.00212 seconds (files took 0.08548 seconds to load)
8 | [32m2 examples, 0 failures[0m
9 |
10 |
--------------------------------------------------------------------------------
/04-acceptance-specs/02/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [32m.[0m
6 |
7 | Finished in 0.01528 seconds (files took 0.1276 seconds to load)
8 | [32m1 example, 0 failures[0m
9 |
10 |
--------------------------------------------------------------------------------
/04-acceptance-specs/03/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [32m.[0m
6 |
7 | Finished in 0.01466 seconds (files took 0.131 seconds to load)
8 | [32m1 example, 0 failures[0m
9 |
10 |
--------------------------------------------------------------------------------
/04-acceptance-specs/04/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [32m.[0m
6 |
7 | Finished in 0.0183 seconds (files took 0.13128 seconds to load)
8 | [32m1 example, 0 failures[0m
9 |
10 |
--------------------------------------------------------------------------------
/04-acceptance-specs/05/expense_tracker/app/api.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 |
4 | module ExpenseTracker
5 | class API < Sinatra::Base
6 | post '/expenses' do
7 | JSON.generate('expense_id' => 42)
8 | end
9 |
10 | get '/expenses/:date' do
11 | JSON.generate([])
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/04-acceptance-specs/05/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [32m.[0m
6 |
7 | Finished in 0.01998 seconds (files took 0.13262 seconds to load)
8 | [32m1 example, 0 failures[0m
9 |
10 |
--------------------------------------------------------------------------------
/04-acceptance-specs/05/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [32m.[0m
6 |
7 | Finished in 0.01843 seconds (files took 0.13757 seconds to load)
8 | [32m1 example, 0 failures[0m
9 |
10 |
--------------------------------------------------------------------------------
/01-getting-started/01/sessions/check_rspec_version.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec --version
5 | RSpec 3.6
6 | - rspec-core 3.6.0
7 | - rspec-expectations 3.6.0
8 | - rspec-mocks 3.6.0
9 | - rspec-support 3.6.0
10 |
11 |
--------------------------------------------------------------------------------
/02-running-specs/06/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec --only-failures
5 |
6 | To use `--only-failures`, you must first set ↩
7 | `config.example_status_persistence_file_path`.
8 |
9 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/01/custom_matcher/lib/event.rb:
--------------------------------------------------------------------------------
1 | Event = Struct.new(:name, :capacity) do
2 | def purchase_ticket_for(guest)
3 | tickets_sold << guest
4 | end
5 |
6 | def tickets_sold
7 | @tickets_sold ||= []
8 | end
9 |
10 | def inspect
11 | "#"
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/12/api_request_tracker/lib/api_request_tracker.rb:
--------------------------------------------------------------------------------
1 | require 'metrics_reporter'
2 | require 'endpoint'
3 |
4 | class APIRequestTracker
5 | def process(request)
6 | endpoint_description = Endpoint.description_of(request)
7 | MetricsReporter.increment("api.requests.#{endpoint_description}")
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/04-acceptance-specs/01/sessions/initialize_bundler.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ gem install bundler
5 | Successfully installed bundler-1.15.3
6 | 1 gem installed
7 | $ bundle init
8 | Writing new Gemfile to ~/code/expense_tracker/Gemfile
9 |
10 |
--------------------------------------------------------------------------------
/02-running-specs/07/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | Run options: include {:focus=>true}
6 | [32m.[0m
7 |
8 | Finished in 0.00093 seconds (files took 0.07915 seconds to load)
9 | [32m1 example, 0 failures[0m
10 |
11 |
--------------------------------------------------------------------------------
/02-running-specs/08/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | Run options: include {:focus=>true}
6 | [32m.[0m
7 |
8 | Finished in 0.00087 seconds (files took 0.0791 seconds to load)
9 | [32m1 example, 0 failures[0m
10 |
11 |
--------------------------------------------------------------------------------
/06-integration-specs/07/expense_tracker/spec/support/db.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |c|
2 | c.before(:suite) do
3 | Sequel.extension :migration
4 | Sequel::Migrator.run(DB, 'db/migrations')
5 | DB[:expenses].truncate
6 | end
7 |
8 | c.around(:example, :db) do |example|
9 | DB.transaction(rollback: :always) { example.run }
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/08-metadata/04/spec/metadata_inheritance_spec.rb:
--------------------------------------------------------------------------------
1 | require 'pp'
2 |
3 | RSpec.describe Hash, :outer_group do
4 | it 'is used by RSpec for metadata', :fast, :focus do |example|
5 | pp example.metadata
6 | end
7 |
8 | context 'on a nested group' do
9 | it 'is also inherited' do |example|
10 | pp example.metadata
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/15/api_request_tracker/lib/api_request_tracker.rb:
--------------------------------------------------------------------------------
1 | require 'metrics_reporter'
2 | require 'endpoint'
3 |
4 | class APIRequestTracker
5 | def process(request, reporter: MetricsReporter)
6 | endpoint_description = Endpoint.description_of(request)
7 | reporter.increment("api.requests.#{endpoint_description}")
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/06-integration-specs/01/expense_tracker/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | source "https://rubygems.org"
3 |
4 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
5 |
6 | gem 'rspec', '3.6.0'
7 | gem 'coderay', '1.1.1'
8 | gem 'rack-test', '0.7.0'
9 | gem 'sinatra', '2.0.0'
10 | gem 'sequel', '4.48.0'
11 | gem 'sqlite3', '1.3.13'
12 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/04/config_hooks_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | module MyApp
4 | class Configuration
5 | end
6 | end
7 |
8 | RSpec.describe MyApp::Configuration do
9 | it 'can mutate env' do
10 | ENV['FOO'] = '1'
11 | end
12 |
13 | it 'isolates mutations from other examples' do
14 | expect(ENV['FOO']).to eq nil
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/01/expectation_examples.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'rspec/expectations'
3 | include RSpec::Matchers
4 |
5 | ratio = 22 / 7.0
6 | expect(ratio).to be_within(0.1).of(Math::PI)
7 |
8 | numbers = [13, 3, 99]
9 | expect(numbers).to all be_odd
10 |
11 | alphabet = ('a'..'z').to_a
12 | expect(alphabet).to start_with('a').and end_with('z')
13 |
--------------------------------------------------------------------------------
/A3-matcher-cheat-sheet/01/matchers_cheat_sheet.rb:
--------------------------------------------------------------------------------
1 | expect(a).to matcher
2 |
3 | expect(a).not_to matcher
4 | # or
5 | expect(a).to_not matcher
6 |
7 | expect { some_code }.to matcher
8 | #
9 | expect { do_something }.to change(obj, :attr)
10 | # or
11 | expect { do_something }.to change { obj.attr }
12 |
13 | expect { |probe| obj.some_method(&probe) }.to yield_control
14 |
--------------------------------------------------------------------------------
/08-metadata/06/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.define_derived_metadata(type: :model) do |meta|
3 | # ...
4 | meta[:matched_by_type_model] = true
5 | end
6 | end
7 |
8 | RSpec.describe do
9 | it 'matches type: :model', type: :model do |example|
10 | expect(example.metadata).to include(matched_by_type_model: true)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/06/subscription_service/lib/cash_cow.rb:
--------------------------------------------------------------------------------
1 | class CashCow
2 | def self.charge_card(card, amount)
3 | # ...
4 | puts "charged card: #{card}"
5 | end
6 |
7 | def self.bulk_charge_cards(cards_and_amounts)
8 | # ...
9 | cards_and_amounts.each do |card, _|
10 | puts "charged card: #{card}"
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/01-getting-started/02/sandwich_test.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 |
3 | Sandwich = Struct.new(:taste, :toppings)
4 |
5 | class TestSandwich < Minitest::Test
6 | def test_that_sandwich_is_delicious
7 | sandwich = Sandwich.new('delicious', [])
8 |
9 | taste = sandwich.taste
10 |
11 | assert_equal('delicious', taste, 'Sandwich is not delicious')
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/10/api_request_tracker/lib/api_request_tracker.rb:
--------------------------------------------------------------------------------
1 | require 'metrics_reporter'
2 | require 'endpoint'
3 |
4 | class APIRequestTracker
5 | def process(request)
6 | endpoint_description = Endpoint.description_of(request)
7 | reporter = MetricsReporter.new
8 | reporter.increment("api.requests.#{endpoint_description}")
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/06-integration-specs/02/play_with_sequel.irbr:
--------------------------------------------------------------------------------
1 | >> require 'sequel'
2 | => true
3 | >> DB = Sequel.sqlite
4 | => #:sqlite}>
5 | >> DB.create_table(:gems) { String :name }
6 | => nil
7 | >> DB[:gems].insert(name: 'rspec')
8 | => 1
9 | >> DB[:gems].insert(name: 'sinatra')
10 | => 2
11 | >> DB[:gems].all
12 | => [{:name=>"rspec"}, {:name=>"sinatra"}]
13 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/05/expense_tracker/spec/support/db.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |c|
2 | # ...
3 |
4 | c.before(:suite) do
5 | Sequel.extension :migration
6 | Sequel::Migrator.run(DB, 'db/migrations')
7 | DB[:expenses].truncate
8 | end
9 |
10 | c.around(:example, :db) do |example|
11 | DB.transaction(rollback: :always) { example.run }
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/13-understanding-test-doubles/03/stubbed_constants.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'rspec/expectations'
3 | include RSpec::Matchers
4 | require 'rspec/mocks/standalone'
5 |
6 | class PasswordHash
7 | COST_FACTOR = 12
8 |
9 | # ...
10 | end
11 |
12 | stub_const('PasswordHash::COST_FACTOR', 1)
13 |
14 | expect(PasswordHash::COST_FACTOR).to eq 1
15 |
16 | hide_const('ActiveRecord')
17 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/06/subscription_service/lib/recurring_payment.rb:
--------------------------------------------------------------------------------
1 | require 'cash_cow'
2 |
3 | class RecurringPayment
4 | def self.process_subscriptions(subscriptions)
5 | subscriptions.each do |subscription|
6 | CashCow.charge_card(subscription.credit_card, subscription.amount)
7 | # ...send receipt and other stuff...
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/02-running-specs/06/sessions/rspec_runs/5.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec --only-failures
5 | Run options: include {:last_run_status=>"failed"}
6 | [32m.[0m
7 |
8 | Finished in 0.00094 seconds (files took 0.09055 seconds to load)
9 | [32m1 example, 0 failures[0m
10 |
11 |
--------------------------------------------------------------------------------
/08-metadata/12/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.filter_run_when_matching :focus
3 | end
4 |
5 | RSpec.describe "With no examples focused" do
6 | it "only runs if no other examples are focused" do
7 | end
8 | end
9 |
10 | RSpec.describe "With an example focused" do
11 | it "runs alone when focused", :focus => !!ENV['FOCUS_AN_EXAMPLE'] do
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/01-getting-started/08/toaster.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 |
3 | Toaster = Struct.new(:serial) do
4 | def self.find_by_serial(serial)
5 | new(serial)
6 | end
7 | end
8 |
9 | def current_toaster
10 | @current_toaster ||= Toaster.find_by_serial('HHGG42')
11 | end
12 |
13 | current_toaster # to ensure it does not raise errors
14 |
15 | @current_toaster = nil || Toaster.find_by_serial('HHGG42')
16 |
--------------------------------------------------------------------------------
/09-configuring-rspec/01/sessions/rspec_environment_options.txt.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -I PATH Specify PATH to add to $LOAD_PATH (may ↩
5 | be used more than once).
6 | -r, --require PATH Require a file.
7 |
8 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/09/subscription_service/lib/recurring_payment.rb:
--------------------------------------------------------------------------------
1 | require 'cash_cow'
2 |
3 | class RecurringPayment
4 | def self.process_subscriptions(subscriptions, bank: CashCow)
5 | subscriptions.each do |subscription|
6 | bank.charge_card(subscription.credit_card, subscription.amount)
7 | # ...send receipt and other stuff...
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/06-integration-specs/06/expense_tracker/app/ledger.rb:
--------------------------------------------------------------------------------
1 | module ExpenseTracker
2 | RecordResult = Struct.new(:success?, :expense_id, :error_message)
3 |
4 | class Ledger
5 | def record(expense)
6 | DB[:expenses].insert(expense)
7 | id = DB[:expenses].max(:id)
8 | RecordResult.new(true, id, nil)
9 | end
10 |
11 | def expenses_on(date)
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/08-metadata/08/spec/aggregate_failures_spec.rb:
--------------------------------------------------------------------------------
1 | RSpec.describe ':aggregate_failures' do
2 | it 'has :aggregate_failures by default' do |example|
3 | expect(example.metadata).to include(aggregate_failures: true)
4 | end
5 |
6 | it 'can disable :aggregate_failures', aggregate_failures: false do |example|
7 | expect(example.metadata).to include(aggregate_failures: false)
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/13-understanding-test-doubles/exercises/mountain/lib/skier.rb:
--------------------------------------------------------------------------------
1 | module Mountain
2 | class Skier
3 | def initialize(trail_map)
4 | @trail_map = trail_map
5 | end
6 |
7 | def ski_on(trail_name)
8 | difficulty = @trail_map.difficulty(trail_name)
9 | @tired = true if difficulty == :expert
10 | end
11 |
12 | def tired?
13 | @tired
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/A2-using-rspec-with-rails/01/sessions/install_rspec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rails generate rspec:install
5 | [1m[32m create[0m .rspec
6 | [1m[32m create[0m spec
7 | [1m[32m create[0m spec/spec_helper.rb
8 | [1m[32m create[0m spec/rails_helper.rb
9 |
10 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/02/expense_tracker/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | source "https://rubygems.org"
3 |
4 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
5 |
6 | gem 'rspec', '3.6.0'
7 | gem 'coderay', '1.1.1'
8 | gem 'rack-test', '0.7.0'
9 | gem 'sinatra', '2.0.0'
10 | gem 'sequel', '4.48.0'
11 | gem 'sqlite3', '1.3.13'
12 |
13 | gem 'pry', '0.10.4'
14 |
--------------------------------------------------------------------------------
/13-understanding-test-doubles/exercises/mountain/spec/skier_spec.rb:
--------------------------------------------------------------------------------
1 | require 'skier'
2 |
3 | module Mountain
4 | RSpec.describe Skier do
5 | it 'gets tired after skiing a difficult slope' do
6 | trail_map = instance_double('TrailMap', difficulty: :expert)
7 |
8 | skier = Skier.new(trail_map)
9 | skier.ski_on('Last Hoot')
10 | expect(skier).to be_tired
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/02-running-specs/06/sessions/rspec_runs/6.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec --only-failures
5 | Run options: include {:last_run_status=>"failed"}
6 |
7 | All examples were filtered out
8 |
9 |
10 | Finished in 0.00031 seconds (files took 0.08117 seconds to load)
11 | [32m0 examples, 0 failures[0m
12 |
13 |
--------------------------------------------------------------------------------
/13-understanding-test-doubles/02/expense_tracker/spec/unit/ledger_double_spec.rb:
--------------------------------------------------------------------------------
1 | RSpec.describe 'Using a ledger double' do
2 | example 'a pure double' do
3 | ledger = double('ExpenseTracker::Ledger')
4 | allow(ledger).to receive(:record)
5 | end
6 |
7 | example 'a verifying double' do
8 | ledger = instance_double('ExpenseTracker::Ledger')
9 | allow(ledger).to receive(:record)
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/05-unit-specs/10/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/unit/app/api_spec.rb
5 | truncated
6 |
7 | Finished in 0.0266 seconds (files took 0.13459 seconds to load)
8 | [32m4 examples, 0 failures[0m
9 |
10 | Randomized with seed 13686
11 |
12 |
--------------------------------------------------------------------------------
/02-running-specs/exercises/spec/tea_spec.rb:
--------------------------------------------------------------------------------
1 | class Tea
2 | end
3 |
4 | RSpec.configure do |config|
5 | config.example_status_persistence_file_path = 'spec/examples.txt'
6 | end
7 |
8 | RSpec.describe Tea do
9 | let(:tea) { Tea.new }
10 |
11 | it 'tastes like Earl Grey' do
12 | expect(tea.flavor).to be :earl_grey
13 | end
14 |
15 | it 'is hot' do
16 | expect(tea.temperature).to be > 200.0
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/05-unit-specs/03/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/unit/app/api_spec.rb
5 | truncated
6 |
7 | Finished in 0.02645 seconds (files took 0.14491 seconds to load)
8 | [33m4 examples, 0 failures, 3 pending[0m
9 |
10 | Randomized with seed 23924
11 |
12 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/solutions/calendar_spec.rb:
--------------------------------------------------------------------------------
1 | require 'date'
2 |
3 | Calendar = Struct.new(:date_string) do
4 | def on_weekend?
5 | Date.parse(date_string).saturday?
6 | end
7 | end
8 |
9 | RSpec.describe Calendar do
10 | let(:sunday_date) { Calendar.new('Sun, 11 Jun 2017') }
11 |
12 | it 'considers sundays to be on the weekend' do
13 | expect(sunday_date).to be_on_weekend
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/02-running-specs/05/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m[31mF[0m
6 |
7 | truncated
8 |
9 | [31m2 examples, 1 failure[0m
10 |
11 | Failed examples:
12 |
13 | [31mrspec ./spec/coffee_spec.rb:25[0m [36m# A cup of coffee with milk costs $1.25[0m
14 |
15 |
--------------------------------------------------------------------------------
/02-running-specs/06/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m[31mF[0m
6 |
7 | truncated
8 |
9 | [31m2 examples, 1 failure[0m
10 |
11 | Failed examples:
12 |
13 | [31mrspec ./spec/coffee_spec.rb:29[0m [36m# A cup of coffee with milk costs $1.25[0m
14 |
15 |
--------------------------------------------------------------------------------
/06-integration-specs/08/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/integration/app/ledger_spec.rb
5 | truncated
6 |
7 | Finished in 0.01205 seconds (files took 0.15597 seconds to load)
8 | [32m2 examples, 0 failures[0m
9 |
10 | Randomized with seed 38450
11 |
12 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/exercises/calendar_spec.rb:
--------------------------------------------------------------------------------
1 | require 'date'
2 |
3 | Calendar = Struct.new(:date_string) do
4 | def on_weekend?
5 | Date.parse(date_string).saturday?
6 | end
7 | end
8 |
9 | RSpec.describe Calendar do
10 | let(:sunday_date) { Calendar.new('Sun, 11 Jun 2017') }
11 |
12 | it 'considers sundays to be on the weekend' do
13 | expect(sunday_date.on_weekend?).to be true
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/16/api_request_tracker/lib/api_request_tracker.rb:
--------------------------------------------------------------------------------
1 | require 'metrics_reporter'
2 | require 'endpoint'
3 |
4 | class APIRequestTracker
5 | def initialize(reporter: MetricsReporter.new)
6 | @reporter = reporter
7 | end
8 |
9 | def process(request)
10 | endpoint_description = Endpoint.description_of(request)
11 | @reporter.increment("api.requests.#{endpoint_description}")
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/08/subscription_service/lib/recurring_payment.rb:
--------------------------------------------------------------------------------
1 | require 'cash_cow'
2 |
3 | class RecurringPayment
4 | def self.process_subscriptions(subscriptions)
5 | cards_and_amounts = subscriptions.each_with_object({}) do |sub, data|
6 | data[sub.credit_card] = sub.amount
7 | end
8 |
9 | CashCow.bulk_charge_cards(cards_and_amounts)
10 | # ...send receipts and other stuff...
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/12/api_request_tracker/spec/api_request_tracker_spec.rb:
--------------------------------------------------------------------------------
1 | require 'api_request_tracker'
2 |
3 | RSpec.describe APIRequestTracker do
4 | let(:request) { Request.new(:get, '/users') }
5 |
6 | it 'increments the request counter' do
7 | expect(MetricsReporter).to receive(:increment).with(
8 | 'api.requests.get_users'
9 | )
10 |
11 | APIRequestTracker.new.process(request)
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/21/sales_tax/lib/invoice.rb:
--------------------------------------------------------------------------------
1 | require 'my_app'
2 |
3 | class Invoice
4 | def initialize(address, items, tax_client: MyApp.tax_client)
5 | @address = address
6 | @items = items
7 | @tax_client = tax_client
8 | end
9 |
10 | def calculate_total
11 | subtotal = @items.map(&:cost).inject(0, :+)
12 | taxes = subtotal * tax_rate
13 | subtotal + taxes
14 | end
15 |
16 | # ...
17 | end
18 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/06/transit/lib/berlin_transit_ticket.rb:
--------------------------------------------------------------------------------
1 | class BerlinTransitTicket
2 | attr_accessor :starting_station, :ending_station
3 |
4 | def fare
5 | if starting_station == 'Bundestag' && ending_station == 'Leopoldplatz'
6 | 2.7
7 | elsif starting_station == 'Bundestag' && ending_station == 'Birkenwerder'
8 | 3.3
9 | else
10 | raise 'price has not been defined'
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/06/spec/cookie_recipe_should_spec.rb:
--------------------------------------------------------------------------------
1 | class CookieRecipe
2 | attr_reader :ingredients
3 |
4 | def initialize
5 | @ingredients = [:butter, :milk, :flour, :sugar, :eggs, :chocolate_chips]
6 | end
7 | end
8 |
9 | RSpec.describe CookieRecipe, '#ingredients' do
10 | subject { CookieRecipe.new.ingredients }
11 | it { should include(:butter, :milk, :eggs) }
12 | it { should_not include(:fish_oil) }
13 | end
14 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/17/api_request_tracker/lib/api_request_tracker.rb:
--------------------------------------------------------------------------------
1 | require 'metrics_reporter'
2 | require 'endpoint'
3 |
4 | class APIRequestTracker
5 | attr_writer :reporter
6 | def reporter
7 | @reporter ||= MetricsReporter.new
8 | end
9 |
10 | def process(request)
11 | endpoint_description = Endpoint.description_of(request)
12 | reporter.increment("api.requests.#{endpoint_description}")
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/A1-rspec-and-wider-ecosystem/01/sessions/each_spec_bin_rspec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ time (for file in spec/**/*_spec.rb ↩
5 | do bin/rspec $file || exit 1 ↩
6 | done) > /dev/null
7 |
8 | 0.85s user 0.11s system 97% cpu 0.983 total
9 |
10 |
--------------------------------------------------------------------------------
/A1-rspec-and-wider-ecosystem/01/sessions/each_spec_bundle_exec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ time (for file in spec/**/*_spec.rb ↩
5 | do bundle exec rspec $file || exit 1 ↩
6 | done) > /dev/null
7 |
8 | 1.50s user 0.17s system 98% cpu 1.707 total
9 |
10 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/05/generated_example_descriptions.irbr:
--------------------------------------------------------------------------------
1 | >> require 'rspec/expectations'
2 | => true
3 | >> include RSpec::Matchers
4 | => Object
5 |
6 | >> start_with(1).description
7 | => "start with 1"
8 | >> (start_with(1) & end_with(9)).description
9 | => "start with 1 and end with 9"
10 | >> contain_exactly( a_string_starting_with(1) & ending_with(9) ).description
11 | => "contain exactly (a string starting with 1 and ending with 9)"
12 |
--------------------------------------------------------------------------------
/14-customizing-test-doubles/01/and_return.irbr:
--------------------------------------------------------------------------------
1 | >> require 'rspec/mocks/standalone'
2 | => true
3 | >> random = double('Random')
4 | => #
5 |
6 | >> allow(random).to receive(:rand).and_return(0.1, 0.2, 0.3)
7 | => #.rand(any arguments)>
8 | >> random.rand
9 | => 0.1
10 | >> random.rand
11 | => 0.2
12 | >> random.rand
13 | => 0.3
14 | >> random.rand
15 | => 0.3
16 | >> random.rand
17 | => 0.3
18 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/01/password_strength_validator/lib/password_strength_validator.rb:
--------------------------------------------------------------------------------
1 | require 'configuration'
2 |
3 | class PasswordStrengthValidator
4 |
5 | attr_reader :password
6 |
7 | def initialize(password)
8 | @password = password
9 | end
10 |
11 | def strong_enough?
12 | return false unless password.length >= Acme::Config.min_password_length
13 |
14 | # ... more validations ...
15 | true
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/10/api_request_tracker/spec/api_request_tracker_spec.rb:
--------------------------------------------------------------------------------
1 | require 'api_request_tracker'
2 |
3 | RSpec.describe APIRequestTracker do
4 | let(:request) { Request.new(:get, '/users') }
5 |
6 | it 'increments the request counter' do
7 | expect_any_instance_of(MetricsReporter).to receive(:increment).with(
8 | 'api.requests.get_users'
9 | )
10 |
11 | APIRequestTracker.new.process(request)
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/22/sales_tax/spec/integration/invoice_spec.rb:
--------------------------------------------------------------------------------
1 | require 'invoice'
2 |
3 | RSpec.describe Invoice do
4 | let(:address) { Address.new(zip: '98122') } # Seattle zip
5 | let(:items) { [Item.new(cost: 30), Item.new(cost: 70)] }
6 |
7 | it 'calculates the total' do
8 | invoice = Invoice.new(address, items)
9 |
10 | # Seattle's tax rate is 10.1%
11 | expect(invoice.calculate_total).to eq(110.10)
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/06/spec/cookie_recipe_subject_spec.rb:
--------------------------------------------------------------------------------
1 | class CookieRecipe
2 | attr_reader :ingredients
3 |
4 | def initialize
5 | @ingredients = [:butter, :milk, :flour, :sugar, :eggs, :chocolate_chips]
6 | end
7 | end
8 |
9 | RSpec.describe CookieRecipe, '#ingredients' do
10 | subject { CookieRecipe.new.ingredients }
11 | it { is_expected.to include(:butter, :milk, :eggs) }
12 | it { is_expected.not_to include(:fish_oil) }
13 | end
14 |
--------------------------------------------------------------------------------
/06-integration-specs/03/sessions/sequel_migration.out.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec sequel -m ./db/migrations sqlite://db/development.db --echo
5 | truncated
6 |
7 | I, [2017-06-13T13:34:25.536511 #14630] INFO -- : Finished applying ↩
8 | migration version 1, direction: up, took 0.001514 seconds
9 |
10 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/07/custom_matcher/spec/support/matchers.rb:
--------------------------------------------------------------------------------
1 | RSpec::Matchers.define :have_a_balance_of do |amount|
2 | match { |account| account.current_balance == amount }
3 | failure_message { |account| super() + failure_reason(account) }
4 | failure_message_when_negated { |account| super() + failure_reason(account) }
5 |
6 | private
7 |
8 | def failure_reason(account)
9 | ", but had a balance of #{account.current_balance}"
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/02-running-specs/solutions/01/spec/tea_spec.rb:
--------------------------------------------------------------------------------
1 | class Tea
2 | def flavor
3 | :earl_grey
4 | end
5 | end
6 |
7 | RSpec.configure do |config|
8 | config.example_status_persistence_file_path = 'spec/examples.txt'
9 | end
10 |
11 | RSpec.describe Tea do
12 | let(:tea) { Tea.new }
13 |
14 | it 'tastes like Earl Grey' do
15 | expect(tea.flavor).to be :earl_grey
16 | end
17 |
18 | it 'is hot' do
19 | expect(tea.temperature).to be > 200.0
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/04/around_hooks_spec.rb:
--------------------------------------------------------------------------------
1 | module MyApp
2 | class Configuration
3 | end
4 | end
5 |
6 | RSpec.describe MyApp::Configuration do
7 | around(:example) do |ex|
8 | original_env = ENV.to_hash
9 | ex.run
10 | ENV.replace(original_env)
11 | end
12 |
13 | it 'can mutate env' do
14 | ENV['FOO'] = '1'
15 | end
16 |
17 | it 'isolates mutations from other examples' do
18 | expect(ENV['FOO']).to eq nil
19 | end
20 |
21 | end
22 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/14/api_request_tracker/spec/api_request_tracker_spec.rb:
--------------------------------------------------------------------------------
1 | require 'api_request_tracker'
2 |
3 | RSpec.describe APIRequestTracker do
4 | let(:request) { Request.new(:get, '/users') }
5 |
6 | it 'increments the request counter' do
7 | reporter = class_double(MetricsReporter).as_stubbed_const
8 | expect(reporter).to receive(:increment).with('api.requests.get_users')
9 |
10 | APIRequestTracker.new.process(request)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/15/api_request_tracker/spec/api_request_tracker_spec.rb:
--------------------------------------------------------------------------------
1 | require 'api_request_tracker'
2 |
3 | RSpec.describe APIRequestTracker do
4 | let(:request) { Request.new(:get, '/users') }
5 |
6 | it 'increments the request counter' do
7 | reporter = class_double(MetricsReporter)
8 | expect(reporter).to receive(:increment).with('api.requests.get_users')
9 |
10 | APIRequestTracker.new.process(request, reporter: reporter)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/16/api_request_tracker/spec/api_request_tracker_spec.rb:
--------------------------------------------------------------------------------
1 | require 'api_request_tracker'
2 |
3 | RSpec.describe APIRequestTracker do
4 | let(:request) { Request.new(:get, '/users') }
5 |
6 | it 'increments the request counter' do
7 | reporter = class_double(MetricsReporter)
8 | expect(reporter).to receive(:increment).with('api.requests.get_users')
9 |
10 | APIRequestTracker.new(reporter: reporter).process(request)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/23/sales_tax/lib/sales_tax.rb:
--------------------------------------------------------------------------------
1 | require 'my_app'
2 |
3 | class SalesTax
4 | RateUnavailableError = Class.new(StandardError)
5 |
6 | def initialize(tax_client = MyApp.tax_client)
7 | @tax_client = tax_client
8 | end
9 |
10 | def rate_for(zip)
11 | @tax_client.rates_for_location(zip).combined_rate
12 | rescue Taxjar::Error::NotFound
13 | raise RateUnavailableError, "Sales tax rate unavailable for zip: #{zip}"
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/01-getting-started/09/spec/sandwich_spec.rb:
--------------------------------------------------------------------------------
1 | Sandwich = Struct.new(:taste, :toppings)
2 |
3 | RSpec.describe 'An ideal sandwich' do
4 | let(:sandwich) { Sandwich.new('delicious', []) }
5 |
6 | it 'is delicious' do
7 | taste = sandwich.taste
8 |
9 | expect(taste).to eq('delicious')
10 | end
11 |
12 | it 'lets me add toppings' do
13 | sandwich.toppings << 'cheese'
14 | toppings = sandwich.toppings
15 |
16 | expect(toppings).not_to be_empty
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/21/sales_tax/lib/my_app.rb:
--------------------------------------------------------------------------------
1 | require 'taxjar'
2 | require 'dotenv'
3 | Dotenv.load('api_creds.env')
4 |
5 | Address = Struct.new(:zip) do
6 | def initialize(zip:)
7 | super(zip)
8 | end
9 | end
10 |
11 | Item = Struct.new(:cost) do
12 | def initialize(cost:)
13 | super(cost)
14 | end
15 | end
16 |
17 | module MyApp
18 | def self.tax_client
19 | @tax_client ||= Taxjar::Client.new(api_key: ENV['TAXJAR_API_KEY'])
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/06-integration-specs/09/sessions/curl_failure.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ curl localhost:9292/expenses/2017-06-10 -w "\n"
5 | NameError: uninitialized constant ExpenseTracker::Ledger::DB
6 | ~/code/expense_tracker/app/ledger.rb:17:in `expenses_on'
7 | ~/code/expense_tracker/app/api.rb:25:in `block in '
8 |
9 | truncated
10 |
11 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/solutions/shared_examples_exercise/spec/uri_spec.rb:
--------------------------------------------------------------------------------
1 | require 'uri'
2 | require 'support/shared_examples'
3 |
4 | RSpec.describe URI do
5 | it_behaves_like 'a URI parsing library', URI
6 |
7 | it 'defaults the port for an http URI to 80' do
8 | expect(URI.parse('http://example.com/').port).to eq 80
9 | end
10 |
11 | it 'defaults the port for an https URI to 443' do
12 | expect(URI.parse('https://example.com/').port).to eq 443
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/09-configuring-rspec/02/configuring_rspec/a_spec.rb:
--------------------------------------------------------------------------------
1 | RSpec.describe 'A group with a failure' do
2 | it 'has an example that fails' do
3 | expect(1).to eq 2
4 | end
5 |
6 | it 'has an example that succeeds' do
7 | expect(1).to eq 1
8 | end
9 | end
10 |
11 | RSpec.describe 'Another group with a failure' do
12 | it 'has an example that fails' do
13 | expect(1).to eq 2
14 | end
15 |
16 | it 'has an example that succeeds' do
17 | expect(1).to eq 1
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/24/sales_tax/spec/unit/invoice_spec.rb:
--------------------------------------------------------------------------------
1 | require 'invoice'
2 |
3 | RSpec.describe Invoice do
4 | let(:address) { Address.new(zip: '90210') }
5 | let(:items) { [Item.new(cost: 30), Item.new(cost: 70)] }
6 |
7 | it 'calculates the total' do
8 | sales_tax = instance_double(SalesTax, rate_for: 0.095)
9 |
10 | invoice = Invoice.new(address, items, sales_tax: sales_tax)
11 |
12 | expect(invoice.calculate_total).to eq(109.50)
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/01-getting-started/05/spec/sandwich_spec.rb:
--------------------------------------------------------------------------------
1 | Sandwich = Struct.new(:taste, :toppings)
2 |
3 | RSpec.describe 'An ideal sandwich' do
4 | before { @sandwich = Sandwich.new('delicious', []) }
5 |
6 | it 'is delicious' do
7 | taste = @sandwich.taste
8 |
9 | expect(taste).to eq('delicious')
10 | end
11 |
12 | it 'lets me add toppings' do
13 | @sandwich.toppings << 'cheese'
14 | toppings = @sandwich.toppings
15 |
16 | expect(toppings).not_to be_empty
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/02-running-specs/06/sessions/rspec_runs/3.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec --only-failures
5 | Run options: include {:last_run_status=>"failed"}
6 | [31mF[0m
7 |
8 | truncated
9 |
10 | [31m1 example, 1 failure[0m
11 |
12 | Failed examples:
13 |
14 | [31mrspec ./spec/coffee_spec.rb:29[0m [36m# A cup of coffee with milk costs $1.25[0m
15 |
16 |
--------------------------------------------------------------------------------
/01-getting-started/06/spec/sandwich_spec.rb:
--------------------------------------------------------------------------------
1 | Sandwich = Struct.new(:taste, :toppings)
2 |
3 | RSpec.describe 'An ideal sandwich' do
4 | def sandwich
5 | Sandwich.new('delicious', [])
6 | end
7 |
8 | it 'is delicious' do
9 | taste = sandwich.taste
10 |
11 | expect(taste).to eq('delicious')
12 | end
13 |
14 | it 'lets me add toppings' do
15 | sandwich.toppings << 'cheese'
16 | toppings = sandwich.toppings
17 |
18 | expect(toppings).not_to be_empty
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/06/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec spec/cookie_recipe_spec.rb --format documentation
5 |
6 | CookieRecipe#ingredients
7 | [32m should include :butter, :milk and :eggs[0m
8 | [32m should not include :fish_oil[0m
9 |
10 | Finished in 0.00197 seconds (files took 0.08433 seconds to load)
11 | [32m2 examples, 0 failures[0m
12 |
13 |
--------------------------------------------------------------------------------
/01-getting-started/01/sessions/install_rspec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ gem install rspec -v 3.6.0
5 | Successfully installed rspec-support-3.6.0
6 | Successfully installed rspec-core-3.6.0
7 | Successfully installed diff-lcs-1.3
8 | Successfully installed rspec-expectations-3.6.0
9 | Successfully installed rspec-mocks-3.6.0
10 | Successfully installed rspec-3.6.0
11 | 6 gems installed
12 |
13 |
--------------------------------------------------------------------------------
/04-acceptance-specs/01/expense_tracker/spec/acceptance/expense_tracker_api_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rack/test'
2 | require 'json'
3 |
4 | module ExpenseTracker
5 | RSpec.describe 'Expense Tracker API' do
6 | include Rack::Test::Methods
7 |
8 | it 'records submitted expenses' do
9 | coffee = {
10 | 'payee' => 'Starbucks',
11 | 'amount' => 5.75,
12 | 'date' => '2017-06-10'
13 | }
14 |
15 | post '/expenses', JSON.generate(coffee)
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/02-running-specs/06/sessions/rspec_runs/4.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec --tag last_run_status:failed
5 | Run options: include {:last_run_status=>"failed"}
6 | [31mF[0m
7 |
8 | truncated
9 |
10 | [31m1 example, 1 failure[0m
11 |
12 | Failed examples:
13 |
14 | [31mrspec ./spec/coffee_spec.rb:29[0m [36m# A cup of coffee with milk costs $1.25[0m
15 |
16 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/04/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.around(:example) do |ex|
3 | original_env = ENV.to_hash
4 | ex.run
5 | ENV.replace(original_env)
6 | end
7 | end
8 |
9 | require 'fileutils'
10 |
11 | RSpec.configure do |config|
12 | config.before(:suite) do
13 | # Remove leftover temporary files
14 | FileUtils.rm_rf('tmp')
15 | end
16 | end
17 |
18 | RSpec.configure do |config|
19 | config.before(:all) do
20 | # ...
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec spec/include_examples_spec.rb --format documentation
5 |
6 | HashKVStore
7 | [32m allows you to fetch previously stored values[0m
8 | [32m raises a KeyError when you fetch an unknown key[0m
9 |
10 | Finished in 0.00309 seconds (files took 0.09898 seconds to load)
11 | [32m2 examples, 0 failures[0m
12 |
13 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/06/sessions/rspec_runs/3.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec spec/cookie_recipe_subject_spec.rb --format documentation
5 |
6 | CookieRecipe#ingredients
7 | [32m should include :butter, :milk, and :eggs[0m
8 | [32m should not include :fish_oil[0m
9 |
10 | Finished in 0.00225 seconds (files took 0.08616 seconds to load)
11 | [32m2 examples, 0 failures[0m
12 |
13 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/06/sessions/rspec_runs/4.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec spec/cookie_recipe_should_spec.rb --format documentation
5 |
6 | CookieRecipe#ingredients
7 | [32m should include :butter, :milk, and :eggs[0m
8 | [32m should not include :fish_oil[0m
9 |
10 | Finished in 0.00147 seconds (files took 0.08302 seconds to load)
11 | [32m2 examples, 0 failures[0m
12 |
13 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/13/api_request_tracker/spec/api_request_tracker_spec.rb:
--------------------------------------------------------------------------------
1 | require 'api_request_tracker'
2 |
3 | RSpec.describe APIRequestTracker do
4 | let(:request) { Request.new(:get, '/users') }
5 |
6 | it 'increments the request counter' do
7 | reporter = class_double(MetricsReporter)
8 | stub_const('MetricsReporter', reporter)
9 | expect(reporter).to receive(:increment).with('api.requests.get_users')
10 |
11 | APIRequestTracker.new.process(request)
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/01-getting-started/07/spec/sandwich_spec.rb:
--------------------------------------------------------------------------------
1 | Sandwich = Struct.new(:taste, :toppings)
2 |
3 | RSpec.describe 'An ideal sandwich' do
4 | def sandwich
5 | @sandwich ||= Sandwich.new('delicious', [])
6 | end
7 |
8 | it 'is delicious' do
9 | taste = sandwich.taste
10 |
11 | expect(taste).to eq('delicious')
12 | end
13 |
14 | it 'lets me add toppings' do
15 | sandwich.toppings << 'cheese'
16 | toppings = sandwich.toppings
17 |
18 | expect(toppings).not_to be_empty
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/06/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec spec/cookie_recipe_no_doc_strings_spec.rb --format documentation
5 |
6 | CookieRecipe#ingredients
7 | [32m should include :butter, :milk, and :eggs[0m
8 | [32m should not include :fish_oil[0m
9 |
10 | Finished in 0.00212 seconds (files took 0.08655 seconds to load)
11 | [32m2 examples, 0 failures[0m
12 |
13 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/06/sessions/minimal_matcher_failure.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1) `have_a_balance_of(amount)` fails when the balance does not match
5 | [31mFailure/Error: [0m[32mexpect[0m(account).to have_a_balance_of([1;34m35[0m)[0m
6 | [31m expected # to have a balance of 35[0m
7 | [36m# ./spec/initial_account_spec.rb:17:in `block (2 levels) in
9 |
--------------------------------------------------------------------------------
/02-running-specs/05/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec ./spec/coffee_spec.rb:25
5 | Run options: include {:locations=>{"./spec/coffee_spec.rb"=>[25]}}
6 | [31mF[0m
7 |
8 | truncated
9 |
10 | [31m1 example, 1 failure[0m
11 |
12 | Failed examples:
13 |
14 | [31mrspec ./spec/coffee_spec.rb:25[0m [36m# A cup of coffee with milk costs $1.25[0m
15 |
16 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/18/twitter_user_formatter/spec/twitter_user_formatter_spec.rb:
--------------------------------------------------------------------------------
1 | require 'twitter_user_formatter'
2 |
3 | RSpec.describe TwitterUserFormatter do
4 | it 'describes their homepage' do
5 | user = instance_double(Twitter::User,
6 | name: 'RSpec',
7 | url: 'http://rspec.info')
8 |
9 | formatter = TwitterUserFormatter.new(user)
10 |
11 | expect(formatter.format).to eq("RSpec's website is http://rspec.info")
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/06/spec/cookie_recipe_no_doc_strings_spec.rb:
--------------------------------------------------------------------------------
1 | class CookieRecipe
2 | attr_reader :ingredients
3 |
4 | def initialize
5 | @ingredients = [:butter, :milk, :flour, :sugar, :eggs, :chocolate_chips]
6 | end
7 | end
8 |
9 | RSpec.describe CookieRecipe, '#ingredients' do
10 | specify do
11 | expect(CookieRecipe.new.ingredients).to include(:butter, :milk, :eggs)
12 | end
13 |
14 | specify do
15 | expect(CookieRecipe.new.ingredients).not_to include(:fish_oil)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/17/api_request_tracker/spec/api_request_tracker_spec.rb:
--------------------------------------------------------------------------------
1 | require 'api_request_tracker'
2 |
3 | RSpec.describe APIRequestTracker do
4 | let(:request) { Request.new(:get, '/users') }
5 |
6 | it 'increments the request counter' do
7 | reporter = class_double(MetricsReporter)
8 | expect(reporter).to receive(:increment).with('api.requests.get_users')
9 |
10 | tracker = APIRequestTracker.new
11 | tracker.reporter = reporter
12 | tracker.process(request)
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/A2-using-rspec-with-rails/01/sessions/generate_pterodactyl.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rails generate model pterodactyl
5 | [1m[0m invoke[0m active_record
6 | [1m[32m create[0m db/migrate/20170613203526_create_pterodactyls.rb
7 | [1m[32m create[0m app/models/pterodactyl.rb
8 | [1m[0m invoke[0m rspec
9 | [1m[32m create[0m spec/models/pterodactyl_spec.rb
10 |
11 |
--------------------------------------------------------------------------------
/02-running-specs/solutions/02/spec/tea_spec.rb:
--------------------------------------------------------------------------------
1 | class Tea
2 | def flavor
3 | :earl_grey
4 | end
5 |
6 | def temperature
7 | 205
8 | end
9 | end
10 |
11 | RSpec.configure do |config|
12 | config.example_status_persistence_file_path = 'spec/examples.txt'
13 | end
14 |
15 | RSpec.describe Tea do
16 | let(:tea) { Tea.new }
17 |
18 | it 'tastes like Earl Grey' do
19 | expect(tea.flavor).to be :earl_grey
20 | end
21 |
22 | it 'is hot' do
23 | expect(tea.temperature).to be > 200.0
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/06-integration-specs/09/sessions/rspec_runs/4.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 |
6 | Randomized with seed 14629
7 | [32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m
8 |
9 | Finished in 0.04986 seconds (files took 0.21623 seconds to load)
10 | [32m13 examples, 0 failures[0m
11 |
12 | Randomized with seed 14629
13 |
14 |
--------------------------------------------------------------------------------
/01-getting-started/04/spec/sandwich_spec.rb:
--------------------------------------------------------------------------------
1 | Sandwich = Struct.new(:taste, :toppings)
2 |
3 | RSpec.describe 'An ideal sandwich' do
4 | it 'is delicious' do
5 | sandwich = Sandwich.new('delicious', [])
6 |
7 | taste = sandwich.taste
8 |
9 | expect(taste).to eq('delicious')
10 | end
11 |
12 | it 'lets me add toppings' do
13 | sandwich = Sandwich.new('delicious', [])
14 |
15 | sandwich.toppings << 'cheese'
16 | toppings = sandwich.toppings
17 |
18 | expect(toppings).not_to be_empty
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/exercises/tokenizer_spec.rb:
--------------------------------------------------------------------------------
1 | class Tokenizer
2 | def self.tokenize(string)
3 | string.split(/ +/)
4 | end
5 | end
6 |
7 | RSpec.describe Tokenizer do
8 | let(:text) do
9 | <<-EOS
10 | I am Sam.
11 | Sam I am.
12 | Do you like green eggs and ham?
13 | EOS
14 | end
15 |
16 | it 'tokenizes multiple lines of text' do
17 | tokenized = Tokenizer.tokenize(text)
18 | expect(tokenized.first(6)).to eq ['I', 'am', 'Sam.', 'Sam', 'I', 'am']
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/solutions/tokenizer_spec.rb:
--------------------------------------------------------------------------------
1 | class Tokenizer
2 | def self.tokenize(string)
3 | string.split(/ +/)
4 | end
5 | end
6 |
7 | RSpec.describe Tokenizer do
8 | let(:text) do
9 | <<-EOS
10 | I am Sam.
11 | Sam I am.
12 | Do you like green eggs and ham?
13 | EOS
14 | end
15 |
16 | it 'tokenizes multiple lines of text' do
17 | tokenized = Tokenizer.tokenize(text)
18 | expect(tokenized).to start_with('I', 'am', 'Sam.', 'Sam', 'I', 'am')
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/02/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 |
6 | Randomized with seed 21580
7 | [32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m
8 |
9 | Finished in 0.05467 seconds (files took 0.22211 seconds to load)
10 | [32m13 examples, 0 failures[0m
11 |
12 | Randomized with seed 21580
13 |
14 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/03/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 |
6 | Randomized with seed 39552
7 | [32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m
8 |
9 | Finished in 0.04785 seconds (files took 0.2185 seconds to load)
10 | [32m13 examples, 0 failures[0m
11 |
12 | Randomized with seed 39552
13 |
14 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/04/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 |
6 | Randomized with seed 21225
7 | [32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m
8 |
9 | Finished in 0.05466 seconds (files took 0.20993 seconds to load)
10 | [32m13 examples, 0 failures[0m
11 |
12 | Randomized with seed 21225
13 |
14 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/11/api_request_tracker/spec/api_request_tracker_spec.rb:
--------------------------------------------------------------------------------
1 | require 'api_request_tracker'
2 |
3 | RSpec.describe APIRequestTracker do
4 | let(:request) { Request.new(:get, '/users') }
5 |
6 | it 'increments the request counter' do
7 | reporter = instance_double(MetricsReporter)
8 | allow(MetricsReporter).to receive(:new).and_return(reporter)
9 | expect(reporter).to receive(:increment).with('api.requests.get_users')
10 |
11 | APIRequestTracker.new.process(request)
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec spec/hash_kv_store_spec.rb --format documentation
5 |
6 | HashKVStore
7 | behaves like KV store
8 | [32m allows you to fetch previously stored values[0m
9 | [32m raises a KeyError when you fetch an unknown key[0m
10 |
11 | Finished in 0.0034 seconds (files took 0.09656 seconds to load)
12 | [32m2 examples, 0 failures[0m
13 |
14 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/sessions/rspec_runs/5.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec spec/pass_block_spec.rb --format documentation
5 |
6 | FileKVStore
7 | behaves like KV store
8 | [32m allows you to fetch previously stored values[0m
9 | [32m raises a KeyError when you fetch an unknown key[0m
10 |
11 | Finished in 0.00279 seconds (files took 0.10623 seconds to load)
12 | [32m2 examples, 0 failures[0m
13 |
14 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/24/sales_tax/lib/invoice.rb:
--------------------------------------------------------------------------------
1 | require 'my_app'
2 | require 'sales_tax'
3 |
4 | class Invoice
5 | def initialize(address, items, sales_tax: SalesTax.new)
6 | @address = address
7 | @items = items
8 | @sales_tax = sales_tax
9 | end
10 |
11 | def calculate_total
12 | subtotal = @items.map(&:cost).inject(0, :+)
13 | taxes = subtotal * tax_rate
14 | subtotal + taxes
15 | end
16 |
17 | private
18 |
19 | def tax_rate
20 | @sales_tax.rate_for(@address.zip)
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/05-unit-specs/03/expense_tracker/app/api.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 |
4 | module ExpenseTracker
5 | class API < Sinatra::Base
6 | def initialize(ledger: Ledger.new)
7 | @ledger = ledger
8 | super()
9 | end
10 |
11 | post '/expenses' do
12 | expense = JSON.parse(request.body.read)
13 | result = @ledger.record(expense)
14 | JSON.generate('expense_id' => result.expense_id)
15 | end
16 |
17 | get '/expenses/:date' do
18 | JSON.generate([])
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/22/sales_tax/lib/invoice.rb:
--------------------------------------------------------------------------------
1 | require 'my_app'
2 |
3 | class Invoice
4 | def initialize(address, items, tax_client: MyApp.tax_client)
5 | @address = address
6 | @items = items
7 | @tax_client = tax_client
8 | end
9 |
10 | def calculate_total
11 | subtotal = @items.map(&:cost).inject(0, :+)
12 | taxes = subtotal * tax_rate
13 | subtotal + taxes
14 | end
15 |
16 | private
17 |
18 | def tax_rate
19 | @tax_client.rates_for_location(@address.zip).combined_rate
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/24/sales_tax/spec/integration/sales_tax_spec.rb:
--------------------------------------------------------------------------------
1 | require 'sales_tax'
2 |
3 | RSpec.describe SalesTax do
4 | let(:sales_tax) { SalesTax.new }
5 |
6 | it 'can fetch the tax rate for a given zip' do
7 | rate = sales_tax.rate_for('90210')
8 | expect(rate).to be_a(Float).and be_between(0.01, 0.5)
9 | end
10 |
11 | it 'raises an error if the tax rate cannot be found' do
12 | expect {
13 | sales_tax.rate_for('00000')
14 | }.to raise_error(SalesTax::RateUnavailableError)
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/04-acceptance-specs/04/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) Expense Tracker API records submitted expenses
10 | [31mFailure/Error: [0mparsed = [1;34;4mJSON[0m.parse(last_response.body)[0m
11 | [31m[0m
12 | [31mJSON::ParserError:[0m
13 | [31m 743: unexpected token at ''[0m
14 |
15 | truncated
16 |
17 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/shared_examples/lib/file_kv_store.rb:
--------------------------------------------------------------------------------
1 | require 'tempfile'
2 | require 'pstore'
3 |
4 | class FileKVStore
5 | def initialize(filename = Tempfile.new('pstore').path)
6 | @pstore = PStore.new(filename)
7 | end
8 |
9 | def store(key, value)
10 | @pstore.transaction do
11 | @pstore[key] = value
12 | end
13 | end
14 |
15 | def fetch(key)
16 | @pstore.transaction do
17 | @pstore.fetch(key)
18 | end
19 | rescue PStore::Error => e
20 | raise KeyError, e.message
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/08-metadata/07/aggregate_failures.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'rspec'
3 |
4 | RSpec.configure do |config|
5 | config.define_derived_metadata do |meta|
6 | # Sets the flag unconditionally;
7 | # doesn't allow examples to opt out
8 | meta[:aggregate_failures] = true
9 | end
10 | end
11 |
12 | RSpec.describe 'Billing', aggregate_failures: false do
13 | context 'using the fake payment service' do
14 | before do
15 | expect(MyApp.config.payment_gateway).to include('sandbox')
16 | end
17 |
18 | # ...
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/19/ruby_doc_server/spec/ruby_doc_server_spec.rb:
--------------------------------------------------------------------------------
1 | require 'ruby_doc_server'
2 |
3 | RSpec.describe RubyDocServer do
4 | it 'finds matching ruby methods' do
5 | out = get('/Array/max')
6 |
7 | expect(out).to have_received(:puts).with('Content-Type: application/json')
8 | expect(out).to have_received(:puts).with('["max","max_by"]')
9 | end
10 |
11 | def get(path)
12 | output = object_spy($stdout)
13 | RubyDocServer.new(output: output).process_request(path)
14 | output
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/04-acceptance-specs/02/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) Expense Tracker API records submitted expenses
10 | [31mFailure/Error: [0m[1;34;4mExpenseTracker[0m::[1;34;4mAPI[0m.new[0m
11 | [31m[0m
12 | [31mNameError:[0m
13 | [31m uninitialized constant ExpenseTracker::API[0m
14 |
15 | truncated
16 |
17 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/solutions/shared_examples_exercise/spec/addressable_spec.rb:
--------------------------------------------------------------------------------
1 | require 'addressable'
2 | require 'support/shared_examples'
3 |
4 | RSpec.describe Addressable do
5 | it_behaves_like 'a URI parsing library', Addressable::URI
6 |
7 | it 'does not default the port for an http URI' do
8 | expect(Addressable::URI.parse('http://example.com/').port).to eq nil
9 | end
10 |
11 | it 'does not default the port for an https URI' do
12 | expect(Addressable::URI.parse('https://example.com/').port).to eq nil
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/A1-rspec-and-wider-ecosystem/02/expense_tracker/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rspec/core/rake_task'
2 | RSpec::Core::RakeTask.new(:spec)
3 |
4 | require 'rspec/core/rake_task'
5 |
6 | namespace :spec do
7 | desc 'Runs unit specs'
8 | RSpec::Core::RakeTask.new(:unit) do |t|
9 | t.pattern = 'spec/unit/**/*_spec.rb'
10 | t.rspec_opts = ['--profile']
11 | end
12 | end
13 |
14 | begin
15 | require 'rspec/core/rake_task'
16 | RSpec::Core::RakeTask.new(:spec)
17 | rescue LoadError
18 | puts 'Spec tasks not defined since RSpec is unavailable'
19 | end
20 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/07/sessions/improved_matcher_failure.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1) `have_a_balance_of(amount)` fails when the balance does not match
5 | [31mFailure/Error: [0m[32mexpect[0m(account).to have_a_balance_of([1;34m35[0m)[0m
6 | [31m expected # to have a balance of 35, but had a ↩
7 | balance of 30[0m
8 | [36m# ./spec/initial_account_spec.rb:17:in `block (2 levels) in
10 |
--------------------------------------------------------------------------------
/13-understanding-test-doubles/02/expense_tracker/app/api.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 |
4 | module ExpenseTracker
5 | class API < Sinatra::Base
6 | def initialize(ledger: Ledger.new)
7 | @ledger = ledger
8 | super()
9 | end
10 |
11 | post '/expenses' do
12 | expense = JSON.parse(request.body.read)
13 | result = @ledger.record(expense)
14 | JSON.generate('expense_id' => result.expense_id)
15 | end
16 |
17 | get '/expenses/:date' do
18 | JSON.generate([])
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/06-integration-specs/06/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/integration/app/ledger_spec.rb
5 |
6 | Randomized with seed 49398
7 |
8 | ExpenseTracker::Ledger
9 | #record
10 | with a valid expense
11 | [32m successfully saves the expense in the DB[0m
12 |
13 | Finished in 0.01121 seconds (files took 0.15597 seconds to load)
14 | [32m1 example, 0 failures[0m
15 |
16 | Randomized with seed 49398
17 |
18 |
--------------------------------------------------------------------------------
/08-metadata/10/spec/music_storage_spec.rb:
--------------------------------------------------------------------------------
1 | class S3Client
2 | def self.for(type)
3 | return if type == :real || type == :memory
4 | raise "Invalid: #{type.inspect}"
5 | end
6 | end
7 |
8 | RSpec.describe 'Music storage' do
9 | let(:s3_client) do |example|
10 | S3Client.for(example.metadata[:s3_adapter])
11 | end
12 |
13 | it 'stores music on the real S3', s3_adapter: :real do
14 | # ...
15 | end
16 |
17 | it 'stores music on an in-memory S3', s3_adapter: :memory do
18 | # ...
19 | end
20 |
21 | before { s3_client }
22 | end
23 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/01/password_strength_validator/spec/password_strength_validator_spec.rb:
--------------------------------------------------------------------------------
1 | require 'password_strength_validator'
2 |
3 | RSpec.describe PasswordStrengthValidator do
4 | it 'rejects passwords shorter than 8 characters' do
5 | validator = PasswordStrengthValidator.new('a8E^rd2')
6 | expect(validator.strong_enough?).to eq false
7 | end
8 |
9 | it 'accepts passwords 8 characters or longer' do
10 | validator = PasswordStrengthValidator.new('a8E^rd2i')
11 | expect(validator.strong_enough?).to eq true
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/09-configuring-rspec/04/configuring_rspec/mocha_spec.rb:
--------------------------------------------------------------------------------
1 | class PointOfSale
2 | def self.purchase(item, with: nil)
3 | with.charge(item.cost)
4 | end
5 | end
6 |
7 | RSpec.configure do |config|
8 | config.mock_with :mocha
9 | end
10 |
11 | RSpec.describe 'config.mock_with :mocha' do
12 | it 'allows you to use mocha instead of rspec-mocks' do
13 | item = stub('Book', cost: 17.50)
14 |
15 | credit_card = mock('CreditCard')
16 | credit_card.expects(:charge).with(17.50)
17 |
18 | PointOfSale.purchase(item, with: credit_card)
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/06-integration-specs/08/expense_tracker/app/ledger.rb:
--------------------------------------------------------------------------------
1 | module ExpenseTracker
2 | RecordResult = Struct.new(:success?, :expense_id, :error_message)
3 |
4 | class Ledger
5 | def record(expense)
6 | unless expense.key?('payee')
7 | message = 'Invalid expense: `payee` is required'
8 | return RecordResult.new(false, nil, message)
9 | end
10 |
11 | DB[:expenses].insert(expense)
12 | id = DB[:expenses].max(:id)
13 | RecordResult.new(true, id, nil)
14 | end
15 |
16 | def expenses_on(date)
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/06/spec/cookie_recipe_spec.rb:
--------------------------------------------------------------------------------
1 | class CookieRecipe
2 | attr_reader :ingredients
3 |
4 | def initialize
5 | @ingredients = [:butter, :milk, :flour, :sugar, :eggs, :chocolate_chips]
6 | end
7 | end
8 |
9 | RSpec.describe CookieRecipe, '#ingredients' do
10 | it 'should include :butter, :milk and :eggs' do
11 | expect(CookieRecipe.new.ingredients).to include(:butter, :milk, :eggs)
12 | end
13 |
14 | it 'should not include :fish_oil' do
15 | expect(CookieRecipe.new.ingredients).not_to include(:fish_oil)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/05-unit-specs/04/expense_tracker/app/api.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 |
4 | module ExpenseTracker
5 | class API < Sinatra::Base
6 | def initialize(ledger: Ledger.new)
7 | @ledger = ledger
8 | super()
9 | end
10 |
11 | post '/expenses' do
12 | status 404
13 |
14 | expense = JSON.parse(request.body.read)
15 | result = @ledger.record(expense)
16 | JSON.generate('expense_id' => result.expense_id)
17 | end
18 |
19 |
20 | get '/expenses/:date' do
21 | JSON.generate([])
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/02-running-specs/01/spec/coffee_spec.rb:
--------------------------------------------------------------------------------
1 | class Coffee
2 | def ingredients
3 | @ingredients ||= []
4 | end
5 |
6 | def add(ingredient)
7 | ingredients << ingredient
8 | end
9 |
10 | def price
11 | 1.00
12 | end
13 | end
14 |
15 | RSpec.describe 'A cup of coffee' do
16 | let(:coffee) { Coffee.new }
17 |
18 | it 'costs $1' do
19 | expect(coffee.price).to eq(1.00)
20 | end
21 |
22 | context 'with milk' do
23 | before { coffee.add :milk }
24 |
25 | it 'costs $1.25' do
26 | expect(coffee.price).to eq(1.25)
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/20/ruby_doc_server/spec/ruby_doc_server_spec.rb:
--------------------------------------------------------------------------------
1 | require 'ruby_doc_server'
2 | require 'stringio'
3 |
4 | RSpec.describe RubyDocServer do
5 | it 'finds matching ruby methods' do
6 | result = get('/Array/min')
7 |
8 | expect(result.split("\n")).to eq [
9 | 'Content-Type: application/json',
10 | '',
11 | '["min","min_by","minmax","minmax_by"]'
12 | ]
13 | end
14 |
15 | def get(path)
16 | output = StringIO.new
17 | RubyDocServer.new(output: output).process_request(path)
18 | output.string
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/22/sales_tax/spec/unit/invoice_spec.rb:
--------------------------------------------------------------------------------
1 | require 'invoice'
2 |
3 | RSpec.describe Invoice do
4 | let(:address) { Address.new(zip: '90210') }
5 | let(:items) { [Item.new(cost: 30), Item.new(cost: 70)] }
6 |
7 | it 'calculates the total' do
8 | tax_rate = instance_double(Taxjar::Rate, combined_rate: 0.095)
9 | tax_client = instance_double(Taxjar::Client, rates_for_location: tax_rate)
10 |
11 | invoice = Invoice.new(address, items, tax_client: tax_client)
12 |
13 | expect(invoice.calculate_total).to eq(109.50)
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/10/shared_examples/spec/hash_kv_store_spec.rb:
--------------------------------------------------------------------------------
1 | require 'hash_kv_store'
2 |
3 | RSpec.describe HashKVStore do
4 | let(:kv_store) { HashKVStore.new }
5 |
6 | it 'allows you to fetch previously stored values' do
7 | kv_store.store(:language, 'Ruby')
8 | kv_store.store(:os, 'linux')
9 |
10 | expect(kv_store.fetch(:language)).to eq 'Ruby'
11 | expect(kv_store.fetch(:os)).to eq 'linux'
12 | end
13 |
14 | it 'raises a KeyError when you fetch an unknown key' do
15 | expect { kv_store.fetch(:foo) }.to raise_error(KeyError)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/shared_examples/spec/support/kv_store_shared_examples.rb:
--------------------------------------------------------------------------------
1 | RSpec.shared_examples 'KV store' do |kv_store_class|
2 | let(:kv_store) { kv_store_class.new }
3 |
4 | it 'allows you to fetch previously stored values' do
5 | kv_store.store(:language, 'Ruby')
6 | kv_store.store(:os, 'linux')
7 |
8 | expect(kv_store.fetch(:language)).to eq 'Ruby'
9 | expect(kv_store.fetch(:os)).to eq 'linux'
10 | end
11 |
12 | it 'raises a KeyError when you fetch an unknown key' do
13 | expect { kv_store.fetch(:foo) }.to raise_error(KeyError)
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/09-configuring-rspec/04/configuring_rspec/expect_with_spec.rb:
--------------------------------------------------------------------------------
1 | require 'wrong'
2 |
3 | RSpec.configure do |config|
4 | config.expect_with :minitest, :rspec, Wrong
5 | end
6 |
7 | RSpec.describe 'Using different assertion/expectation libraries' do
8 | let(:result) { 2 + 2 }
9 |
10 | it 'works with minitest assertions' do
11 | assert_equal 4, result
12 | end
13 |
14 | it 'works with rspec expectations' do
15 | expect(result).to eq 4
16 | end
17 |
18 | it 'works with wrong' do
19 | # "Where 2 and 2 always makes 5..."
20 | assert { result == 5 }
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/solutions/custom_matcher/spec/support/event_matchers.rb:
--------------------------------------------------------------------------------
1 | RSpec::Matchers.define :have_no_tickets_sold do
2 | match { |event| event.tickets_sold.count.zero? }
3 |
4 | failure_message do |event|
5 | super() + ", but had #{event.tickets_sold.count}"
6 | end
7 | end
8 |
9 | RSpec::Matchers.define :be_sold_out do
10 | match { |event| event.tickets_sold.count == event.capacity }
11 |
12 | failure_message do |event|
13 | unsold_count = event.capacity - event.tickets_sold.count
14 | super() + ", but had #{unsold_count} unsold tickets"
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/04-acceptance-specs/03/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) Expense Tracker API records submitted expenses
10 | [31mFailure/Error: [0m[32mexpect[0m(last_response.status).to eq([1;34m200[0m)[0m
11 | [31m[0m
12 | [31m expected: 200[0m
13 | [31m got: 404[0m
14 | [31m[0m
15 | [31m (compared using ==)[0m
16 |
17 | truncated
18 |
19 |
--------------------------------------------------------------------------------
/04-acceptance-specs/05/sessions/rspec_runs/3.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) Expense Tracker API records submitted expenses
10 | [31mFailure/Error: [0m[32mexpect[0m(last_response.status).to eq([1;34m200[0m)[0m
11 | [31m[0m
12 | [31m expected: 200[0m
13 | [31m got: 404[0m
14 | [31m[0m
15 | [31m (compared using ==)[0m
16 |
17 | truncated
18 |
19 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/02/good_failure_messages.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'rspec/expectations'
3 | include RSpec::Matchers
4 |
5 | ENME = RSpec::Expectations::ExpectationNotMetError
6 |
7 | def self.heredoc_without_markers(heredoc)
8 | heredoc.chomp.split("\n").reject { |l| l =~ /# (START|END)/ }.join("\n")
9 | end
10 |
11 | expect {
12 | expect([13, 2, 3, 99]).to all be_odd
13 | }.to raise_error(ENME, heredoc_without_markers(<<-EOM))
14 | expected [13, 2, 3, 99] to all be odd
15 |
16 | object at index 1 failed to match:
17 | expected `2.odd?` to return true, got false
18 | EOM
19 |
--------------------------------------------------------------------------------
/05-unit-specs/02/expense_tracker/spec/unit/app/api_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative '../../../app/api'
2 |
3 | module ExpenseTracker
4 | RSpec.describe API do
5 | describe 'POST /expenses' do
6 | context 'when the expense is successfully recorded' do
7 | it 'returns the expense id'
8 | it 'responds with a 200 (OK)'
9 | end
10 |
11 | # ... next context will go here...
12 |
13 | context 'when the expense fails validation' do
14 | it 'returns an error message'
15 | it 'responds with a 422 (Unprocessable entity)'
16 | end
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/04-acceptance-specs/02/expense_tracker/spec/acceptance/expense_tracker_api_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rack/test'
2 | require 'json'
3 | require_relative '../../app/api'
4 |
5 | module ExpenseTracker
6 | RSpec.describe 'Expense Tracker API' do
7 | include Rack::Test::Methods
8 |
9 | def app
10 | ExpenseTracker::API.new
11 | end
12 |
13 | it 'records submitted expenses' do
14 | coffee = {
15 | 'payee' => 'Starbucks',
16 | 'amount' => 5.75,
17 | 'date' => '2017-06-10'
18 | }
19 |
20 | post '/expenses', JSON.generate(coffee)
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/04-acceptance-specs/06/sessions/boot_app.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rackup
5 | [2017-06-13 13:34:10] INFO WEBrick 1.3.1
6 | [2017-06-13 13:34:10] INFO ruby 2.4.1 (2017-03-22) [x86_64-darwin15]
7 | [2017-06-13 13:34:10] INFO WEBrick::HTTPServer#start: pid=45203 port=9292
8 | ::1 - - [13/Jun/2017:13:34:10 -0700] "GET /expenses/2017-06-10 HTTP/1.1" ↩
9 | 200 2 0.0046
10 | [2017-06-13 13:34:10] INFO going to shutdown ...
11 | [2017-06-13 13:34:10] INFO WEBrick::HTTPServer#start done.
12 |
13 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/exercises/shared_examples_exercise/spec/uri_spec.rb:
--------------------------------------------------------------------------------
1 | require 'uri'
2 |
3 | RSpec.describe URI do
4 | it 'parses the host' do
5 | expect(URI.parse('http://foo.com/').host).to eq 'foo.com'
6 | end
7 |
8 | it 'parses the port' do
9 | expect(URI.parse('http://example.com:9876').port).to eq 9876
10 | end
11 |
12 | it 'defaults the port for an http URI to 80' do
13 | expect(URI.parse('http://example.com/').port).to eq 80
14 | end
15 |
16 | it 'defaults the port for an https URI to 443' do
17 | expect(URI.parse('https://example.com/').port).to eq 443
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/06/custom_matcher/spec/initial_account_spec.rb:
--------------------------------------------------------------------------------
1 | require 'account'
2 | require 'support/matchers'
3 |
4 | RSpec.describe '`have_a_balance_of(amount)`' do
5 | let(:account) { Account.new('Checking') }
6 |
7 | before do
8 | account.expenses << Expense.new(Date.new(2017, 6, 10), 10)
9 | account.expenses << Expense.new(Date.new(2017, 6, 15), 20)
10 | end
11 |
12 | it 'passes when the balance matches' do
13 | expect(account).to have_a_balance_of(30)
14 | end
15 |
16 | it 'fails when the balance does not match' do
17 | expect(account).to have_a_balance_of(35)
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/08-metadata/exercises/expense_tracker/spec/support/db.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |c|
2 | # ...
3 |
4 | c.before(:suite) do
5 | Sequel.extension :migration
6 | Sequel::Migrator.run(DB, 'db/migrations')
7 | DB[:expenses].truncate
8 |
9 | FileUtils.mkdir_p('log')
10 | require 'logger'
11 | DB.loggers << Logger.new('log/sequel.log')
12 | end
13 |
14 | c.around(:example, :db) do |example|
15 | DB.log_info "Starting example: #{example.metadata[:description]}"
16 | DB.transaction(rollback: :always) { example.run }
17 | DB.log_info "Ending example: #{example.metadata[:description]}"
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/06/custom_matcher/lib/account.rb:
--------------------------------------------------------------------------------
1 | require 'date'
2 |
3 | Account = Struct.new(:name) do
4 | def expenses
5 | @expenses ||= []
6 | end
7 |
8 | def current_balance
9 | calculate_balance(expenses)
10 | end
11 |
12 | def balance_as_of(date)
13 | calculate_balance(expenses.select { |e| e.date <= date })
14 | end
15 |
16 | def to_s
17 | super.sub('struct ', '')
18 | end
19 | alias_method :inspect, :to_s
20 |
21 | private
22 |
23 | def calculate_balance(expenses)
24 | expenses.map(&:amount).inject(0, :+)
25 | end
26 | end
27 |
28 | Expense = Struct.new(:date, :amount)
29 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/03/daily_summary_email/lib/daily_summary.rb:
--------------------------------------------------------------------------------
1 | class DailySummary
2 | def send_daily_summary(user_email, todays_messages)
3 | message_count = todays_messages.count
4 | thread_count = todays_messages.map { |m| m[:thread_id] }.uniq.count
5 | subject = 'Your daily message summary'
6 | body = "You missed #{message_count} messages " \
7 | "in #{thread_count} threads today"
8 |
9 | deliver(email: user_email, subject: subject, body: body)
10 | end
11 |
12 | def deliver(email:, subject:, body:)
13 | # send the message via SMTP
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/08-metadata/11/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | if ENV['SIMULATE_JRUBY']
2 | original_ruby_platform = RUBY_PLATFORM
3 | Object.send(:remove_const, :RUBY_PLATFORM)
4 | RUBY_PLATFORM = 'java'
5 | end
6 |
7 | RSpec.configure do |config|
8 | config.filter_run_excluding :jruby_only unless RUBY_PLATFORM == 'java'
9 | end
10 |
11 | if ENV['SIMULATE_JRUBY']
12 | Object.send(:remove_const, :RUBY_PLATFORM)
13 | RUBY_PLATFORM = original_ruby_platform
14 | end
15 |
16 | RSpec.describe "All rubies" do
17 | it "always runs" do
18 | end
19 | end
20 |
21 | RSpec.describe "Only on JRuby", :jruby_only do
22 | it "always runs" do
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/sessions/rspec_runs/3.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec spec/include_examples_twice_spec.rb --format documentation
5 |
6 | Key-value stores
7 | [32m allows you to fetch previously stored values[0m
8 | [32m raises a KeyError when you fetch an unknown key[0m
9 | [32m allows you to fetch previously stored values[0m
10 | [32m raises a KeyError when you fetch an unknown key[0m
11 |
12 | Finished in 0.00355 seconds (files took 0.10257 seconds to load)
13 | [32m4 examples, 0 failures[0m
14 |
15 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/solutions/shared_examples_exercise/spec/support/shared_examples.rb:
--------------------------------------------------------------------------------
1 | require 'uri'
2 |
3 | RSpec.shared_examples 'a URI parsing library' do |library|
4 | it 'parses the scheme' do
5 | expect(library.parse('https://a.com/').scheme).to eq 'https'
6 | end
7 |
8 | it 'parses the host' do
9 | expect(library.parse('http://foo.com/').host).to eq 'foo.com'
10 | end
11 |
12 | it 'parses the port' do
13 | expect(library.parse('http://example.com:9876').port).to eq 9876
14 | end
15 |
16 | it 'parses the path' do
17 | expect(library.parse('http://a.com/foo').path).to eq '/foo'
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/06-integration-specs/09/sessions/curl_output_success.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ curl localhost:9292/expenses --data '{"payee":"Zoo", "amount":10, ↩
5 | "date":"2017-06-10"}' -w "\n"
6 | {"expense_id":1}
7 | $ curl localhost:9292/expenses --data '{"payee":"Starbucks", "amount":7.5, ↩
8 | "date":"2017-06-10"}' -w "\n"
9 | {"expense_id":2}
10 | $ curl localhost:9292/expenses/2017-06-10 -w "\n"
11 | [{"id":1,"payee":"Zoo","amount":10.0,"date":"2017-06-10"},{"id":2,"payee":"St
12 | arbucks","amount":7.5,"date":"2017-06-10"}]
13 |
14 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/exercises/shared_examples_exercise/spec/addressable_spec.rb:
--------------------------------------------------------------------------------
1 | require 'addressable'
2 |
3 | RSpec.describe Addressable do
4 | it 'parses the scheme' do
5 | expect(Addressable::URI.parse('https://a.com/').scheme).to eq 'https'
6 | end
7 |
8 | it 'parses the host' do
9 | expect(Addressable::URI.parse('https://foo.com/').host).to eq 'foo.com'
10 | end
11 |
12 | it 'parses the port' do
13 | expect(Addressable::URI.parse('http://example.com:9876').port).to eq 9876
14 | end
15 |
16 | it 'parses the path' do
17 | expect(Addressable::URI.parse('http://a.com/foo').path).to eq '/foo'
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/02-running-specs/03/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec --profile 2
5 | [32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m
6 |
7 | Top 2 slowest examples (0.90618 seconds, 59.9% of total time):
8 | The sleep() method can sleep for 0.5 second
9 | [1m0.50118[0m [1mseconds[0m ./spec/slow_spec.rb:6
10 | The sleep() method can sleep for 0.4 second
11 | [1m0.40501[0m [1mseconds[0m ./spec/slow_spec.rb:5
12 |
13 | Finished in 1.51 seconds (files took 0.08911 seconds to load)
14 | [32m5 examples, 0 failures[0m
15 |
16 |
--------------------------------------------------------------------------------
/04-acceptance-specs/03/expense_tracker/spec/acceptance/expense_tracker_api_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rack/test'
2 | require 'json'
3 | require_relative '../../app/api'
4 |
5 | module ExpenseTracker
6 | RSpec.describe 'Expense Tracker API' do
7 | include Rack::Test::Methods
8 |
9 | def app
10 | ExpenseTracker::API.new
11 | end
12 |
13 | it 'records submitted expenses' do
14 | coffee = {
15 | 'payee' => 'Starbucks',
16 | 'amount' => 5.75,
17 | 'date' => '2017-06-10'
18 | }
19 |
20 | post '/expenses', JSON.generate(coffee)
21 | expect(last_response.status).to eq(200)
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/06-integration-specs/08/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec --seed 32043
5 | truncated
6 |
7 | Finished in 0.05786 seconds (files took 0.22818 seconds to load)
8 | [31m11 examples, 1 failure, 1 pending[0m
9 |
10 | Failed examples:
11 |
12 | [31mrspec ./spec/integration/app/ledger_spec.rb:33[0m [36m# ↩
13 | ExpenseTracker::Ledger#record when the expense lacks a payee rejects the ↩
14 | expense as invalid[0m
15 |
16 | Randomized with seed 32043
17 |
18 |
--------------------------------------------------------------------------------
/06-integration-specs/09/expense_tracker/app/ledger.rb:
--------------------------------------------------------------------------------
1 | require_relative '../config/sequel'
2 |
3 | module ExpenseTracker
4 | RecordResult = Struct.new(:success?, :expense_id, :error_message)
5 |
6 | class Ledger
7 | def record(expense)
8 | unless expense.key?('payee')
9 | message = 'Invalid expense: `payee` is required'
10 | return RecordResult.new(false, nil, message)
11 | end
12 |
13 | DB[:expenses].insert(expense)
14 | id = DB[:expenses].max(:id)
15 | RecordResult.new(true, id, nil)
16 | end
17 |
18 | def expenses_on(date)
19 | DB[:expenses].where(date: date).all
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/09/sessions/composed_matcher_failure.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1) `have_a_balance_of(amount)` fails when the balance does not match
5 | [31mFailure/Error: [0m[32mexpect[0m(account).to ↩
6 | have_a_balance_of(a_value_within([1;34m1[0m).of([1;34m10_499_999[0m))[0m
7 | [31m expected # to have a balance of a value ↩
8 | within 1 of 10499999, but had a balance of 10500000.9[0m
9 | [36m# ./spec/composed_account_spec.rb:19:in `block (2 levels) in
11 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/02/password_strength_validator/spec/password_strength_validator_spec.rb:
--------------------------------------------------------------------------------
1 | require 'password_strength_validator'
2 |
3 | RSpec.describe PasswordStrengthValidator do
4 | before do
5 | allow(Acme::Config).to receive(:min_password_length).and_return(6)
6 | end
7 |
8 | it 'rejects passwords shorter than the configured length' do
9 | validator = PasswordStrengthValidator.new('a8E^r')
10 | expect(validator.strong_enough?).to eq false
11 | end
12 |
13 | it 'accepts passwords that satisfy the configured length' do
14 | validator = PasswordStrengthValidator.new('a8E^rd')
15 | expect(validator.strong_enough?).to eq true
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/04/daily_summary_email/lib/daily_summary.rb:
--------------------------------------------------------------------------------
1 | require 'email_sender'
2 |
3 | class DailySummary
4 | def initialize(email_sender: EmailSender.new)
5 | @email_sender = email_sender
6 | end
7 |
8 | def send_daily_summary(user_email, todays_messages)
9 | message_count = todays_messages.count
10 | thread_count = todays_messages.map { |m| m[:thread_id] }.uniq.count
11 | subject = 'Your daily message summary'
12 | body = "You missed #{message_count} messages " \
13 | "in #{thread_count} threads today"
14 |
15 | @email_sender.deliver(email: user_email, subject: subject, body: body)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/04-acceptance-specs/01/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) Expense Tracker API records submitted expenses
10 | [31mFailure/Error: [0mpost [31m[1;31m'[0m[31m/expenses[1;31m'[0m[31m[0m, [1;34;4mJSON[0m.generate(coffee)[0m
11 | [31m[0m
12 | [31mNameError:[0m
13 | [31m undefined local variable or method `app' for ↩
14 | #[0m
15 |
16 | truncated
17 |
18 |
--------------------------------------------------------------------------------
/05-unit-specs/07/expense_tracker/app/api.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 |
4 | module ExpenseTracker
5 | class API < Sinatra::Base
6 | def initialize(ledger: Ledger.new)
7 | @ledger = ledger
8 | super()
9 | end
10 |
11 | post '/expenses' do
12 | expense = JSON.parse(request.body.read)
13 | result = @ledger.record(expense)
14 |
15 | if result.success?
16 | JSON.generate('expense_id' => result.expense_id)
17 | else
18 | status 422
19 | JSON.generate('error' => result.error_message)
20 | end
21 | end
22 |
23 | get '/expenses/:date' do
24 | JSON.generate([])
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/sessions/rspec_runs/4.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec spec/it_behaves_like_twice_spec.rb --format documentation
5 |
6 | Key-value stores
7 | behaves like KV store
8 | [32m allows you to fetch previously stored values[0m
9 | [32m raises a KeyError when you fetch an unknown key[0m
10 | behaves like KV store
11 | [32m allows you to fetch previously stored values[0m
12 | [32m raises a KeyError when you fetch an unknown key[0m
13 |
14 | Finished in 0.00337 seconds (files took 0.09726 seconds to load)
15 | [32m4 examples, 0 failures[0m
16 |
17 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/03/daily_summary_email/spec/daily_summary_spec.rb:
--------------------------------------------------------------------------------
1 | require 'daily_summary'
2 |
3 | RSpec.describe DailySummary do
4 | let(:todays_messages) do
5 | [
6 | { thread_id: 1, content: 'Hello world' },
7 | { thread_id: 2, content: 'I think forums are great' },
8 | { thread_id: 2, content: 'Me too!' }
9 | ]
10 | end
11 |
12 | it "sends a summary of today's messages and threads" do
13 | summary = DailySummary.new
14 |
15 | expect(summary).to receive(:deliver).with(
16 | hash_including(body: 'You missed 3 messages in 2 threads today')
17 | )
18 |
19 | summary.send_daily_summary('user@example.com', todays_messages)
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/A1-rspec-and-wider-ecosystem/03/minitest_with_rspec/dinosaur_test.rb:
--------------------------------------------------------------------------------
1 | class Dinosaur
2 | def fly(rocket)
3 | rocket.launch!
4 | @excited = true
5 | end
6 |
7 | def excited?
8 | @excited
9 | end
10 | end
11 |
12 | class Rocket
13 | def launch!
14 | end
15 | end
16 |
17 | require 'minitest/autorun'
18 |
19 | require 'rspec/mocks/minitest_integration'
20 | require 'rspec/expectations/minitest_integration'
21 |
22 | class DinosaurTest < Minitest::Test
23 | def test_dinosaurs_fly_rockets
24 | dinosaur = Dinosaur.new
25 | rocket = instance_double(Rocket)
26 | expect(rocket).to receive(:launch!)
27 | dinosaur.fly(rocket)
28 | expect(dinosaur).to be_excited
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/05-unit-specs/08/expense_tracker/app/api.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 | require_relative 'ledger'
4 |
5 | module ExpenseTracker
6 | class API < Sinatra::Base
7 | def initialize(ledger: Ledger.new)
8 | @ledger = ledger
9 | super()
10 | end
11 |
12 | post '/expenses' do
13 | expense = JSON.parse(request.body.read)
14 | result = @ledger.record(expense)
15 |
16 | if result.success?
17 | JSON.generate('expense_id' => result.expense_id)
18 | else
19 | status 422
20 | JSON.generate('error' => result.error_message)
21 | end
22 | end
23 |
24 | get '/expenses/:date' do
25 | JSON.generate([])
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/02-running-specs/06/spec/coffee_spec.rb:
--------------------------------------------------------------------------------
1 | class Coffee
2 | def ingredients
3 | @ingredients ||= []
4 | end
5 |
6 | def add(ingredient)
7 | ingredients << ingredient
8 | end
9 |
10 | def price
11 | 1.00 + ingredients.size * 0.25
12 | end
13 | end
14 |
15 | RSpec.configure do |config|
16 | config.example_status_persistence_file_path = 'spec/examples.txt'
17 | end
18 |
19 | RSpec.describe 'A cup of coffee' do
20 | let(:coffee) { Coffee.new }
21 |
22 | it 'costs $1' do
23 | expect(coffee.price).to eq(1.00)
24 | end
25 |
26 | context 'with milk' do
27 | before { coffee.add :milk }
28 |
29 | it 'costs $1.25' do
30 | expect(coffee.price).to eq(1.25)
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/solutions/phone_number_extractor_spec.rb:
--------------------------------------------------------------------------------
1 | class PhoneNumberExtractor
2 | def self.extract_from(text, &block)
3 | # Look for patterns like (###) ###-####
4 | text.scan(/(d{3}) d{3}-d{4}/, &block)
5 | end
6 | end
7 |
8 | RSpec.describe PhoneNumberExtractor do
9 | let(:text) do
10 | <<-EOS
11 | Melinda: (202) 555-0168
12 | Bob: 202-555-0199
13 | Sabina: (202) 555-0176
14 | EOS
15 | end
16 |
17 | it 'yields phone numbers as it finds them' do
18 | expect { |probe|
19 | PhoneNumberExtractor.extract_from(text, &probe)
20 | }.to yield_successive_args(
21 | '(202) 555-0168', '202-555-0199', '(202) 555-0175'
22 | )
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/05-unit-specs/07/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/unit/app/api_spec.rb
5 |
6 | Randomized with seed 33950
7 |
8 | ExpenseTracker::API
9 | POST /expenses
10 | when the expense is successfully recorded
11 | [32m returns the expense id[0m
12 | [32m responds with a 200 (OK)[0m
13 | when the expense fails validation
14 | [32m returns an error message[0m
15 | [32m responds with a 422 (Unprocessable entity)[0m
16 |
17 | Finished in 0.02529 seconds (files took 0.13831 seconds to load)
18 | [32m4 examples, 0 failures[0m
19 |
20 | Randomized with seed 33950
21 |
22 |
--------------------------------------------------------------------------------
/01-getting-started/06/sessions/fail_toppings.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m[31mF[0m
6 |
7 | Failures:
8 |
9 | 1) An ideal sandwich lets me add toppings
10 | [31mFailure/Error: expect(toppings).not_to be_empty[0m
11 | [31m expected `[].empty?` to return false, got true[0m
12 | [36m# ./spec/sandwich_spec.rb:18:in `block (2 levels) in '[0m
13 |
14 | Finished in 0.0116 seconds (files took 0.08146 seconds to load)
15 | [31m2 examples, 1 failure[0m
16 |
17 | Failed examples:
18 |
19 | [31mrspec ./spec/sandwich_spec.rb:14[0m [36m# An ideal sandwich lets me add toppings[0m
20 |
21 |
--------------------------------------------------------------------------------
/05-unit-specs/12/expense_tracker/app/api.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 | require_relative 'ledger'
4 |
5 | module ExpenseTracker
6 | class API < Sinatra::Base
7 | def initialize(ledger: Ledger.new)
8 | @ledger = ledger
9 | super()
10 | end
11 |
12 | post '/expenses' do
13 | expense = JSON.parse(request.body.read)
14 | result = @ledger.record(expense)
15 |
16 | if result.success?
17 | JSON.generate('expense_id' => result.expense_id)
18 | else
19 | status 422
20 | JSON.generate('error' => result.error_message)
21 | end
22 | end
23 |
24 | get '/expenses/:date' do
25 | JSON.generate(@ledger.expenses_on(params[:date]))
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/19/ruby_doc_server/lib/ruby_doc_server.rb:
--------------------------------------------------------------------------------
1 | require 'json'
2 |
3 | class RubyDocServer
4 | def initialize(output: $stdout)
5 | @output = output
6 | end
7 |
8 | def process_request(path)
9 | class_name, method_prefix = path.sub(%r{^/}, '').split('/')
10 | klass = Object.const_get(class_name)
11 | methods = klass.instance_methods.grep(/\A#{method_prefix}/).sort
12 | respond_with(methods)
13 | end
14 |
15 | private
16 |
17 | def respond_with(data)
18 | @output.puts 'Content-Type: application/json'
19 | @output.puts
20 | @output.puts JSON.generate(data)
21 | end
22 | end
23 |
24 | if __FILE__.end_with?($PROGRAM_NAME)
25 | RubyDocServer.new.process_request(ENV['PATH_INFO'])
26 | end
27 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/08/sessions/as_of_matcher_failure.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1) `have_a_balance_of(amount)` fails when a date's balance does not match
5 | [31mFailure/Error: [0m[32mexpect[0m(account).to ↩
6 | have_a_balance_of([1;34m15[0m).as_of([1;34;4mDate[0m.new([1;34m2017[0m, [1;34m6[0m, [1;34m12[0m))[0m
7 | [31m expected # to have a balance of 15 as of ↩
8 | #, but had a ↩
9 | balance of 10[0m
10 | [36m# ./spec/as_of_account_spec.rb:19:in `block (2 levels) in
12 |
--------------------------------------------------------------------------------
/01-getting-started/02/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) An ideal sandwich is delicious
10 | [31mFailure/Error: sandwich = Sandwich.new('delicious', [])[0m
11 | [31m[0m
12 | [31mNameError:[0m
13 | [31m uninitialized constant Sandwich[0m
14 | [36m# ./spec/sandwich_spec.rb:4:in `block (2 levels) in '[0m
15 |
16 | Finished in 0.00076 seconds (files took 0.08517 seconds to load)
17 | [31m1 example, 1 failure[0m
18 |
19 | Failed examples:
20 |
21 | [31mrspec ./spec/sandwich_spec.rb:3[0m [36m# An ideal sandwich is delicious[0m
22 |
23 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/06/transit/spec/berlin_transit_ticket_refactored_spec.rb:
--------------------------------------------------------------------------------
1 | require 'berlin_transit_ticket'
2 |
3 | RSpec.describe BerlinTransitTicket do
4 | def fare_for(starting_station, ending_station)
5 | ticket = BerlinTransitTicket.new
6 | ticket.starting_station = starting_station
7 | ticket.ending_station = ending_station
8 | ticket.fare
9 | end
10 |
11 | context 'when starting in zone A and ending in zone B' do
12 | it 'costs €2.70' do
13 | expect(fare_for('Bundestag', 'Leopoldplatz')).to eq 2.7
14 | end
15 | end
16 |
17 | context 'when starting in zone A and ending in zone C' do
18 | it 'costs €3.30' do
19 | expect(fare_for('Bundestag', 'Birkenwerder')).to eq 3.3
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/02-running-specs/07/spec/coffee_spec.rb:
--------------------------------------------------------------------------------
1 | class Coffee
2 | def ingredients
3 | @ingredients ||= []
4 | end
5 |
6 | def add(ingredient)
7 | ingredients << ingredient
8 | end
9 |
10 | def price
11 | 1.00 + ingredients.size * 0.25
12 | end
13 | end
14 |
15 | RSpec.configure do |config|
16 | config.filter_run_when_matching(focus: true)
17 | config.example_status_persistence_file_path = 'spec/examples.txt'
18 | end
19 |
20 | RSpec.describe 'A cup of coffee' do
21 | let(:coffee) { Coffee.new }
22 |
23 | it 'costs $1' do
24 | expect(coffee.price).to eq(1.00)
25 | end
26 |
27 | fcontext 'with milk' do
28 | before { coffee.add :milk }
29 |
30 | it 'costs $1.25' do
31 | expect(coffee.price).to eq(1.25)
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/09/custom_matcher/spec/composed_account_spec.rb:
--------------------------------------------------------------------------------
1 | require 'account'
2 | require 'support/matchers'
3 |
4 | RSpec.describe '`have_a_balance_of(amount)`' do
5 | let(:account) { Account.new('Checking') }
6 |
7 | before do
8 | account.expenses << Expense.new(Date.new(2017, 6, 10), 10_000_000.5)
9 | account.expenses << Expense.new(Date.new(2017, 6, 15), 500_000.4)
10 | end
11 |
12 | it 'passes when the balances match' do
13 | expect(account).to have_a_balance_of(a_value < 11_000_000)
14 | # or
15 | expect(account).to have_a_balance_of(a_value_within(50).of(10_500_000))
16 | end
17 |
18 | it 'fails when the balance does not match' do
19 | expect(account).to have_a_balance_of(a_value_within(1).of(10_499_999))
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/02-running-specs/09/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m[32m.[0m[33m*[0m[33m*[0m
6 |
7 | Pending: (Failures listed here are expected and do not affect your suite's ↩
8 | status)
9 | [33m
10 | 1) A cup of coffee with milk is light in color[0m
11 | [36m# Not yet implemented[0m
12 | [36m # ./spec/coffee_spec.rb:34
13 | [0m[33m
14 | 2) A cup of coffee with milk is cooler than 200 degrees Fahrenheit[0m
15 | [36m# Not yet implemented[0m
16 | [36m # ./spec/coffee_spec.rb:35
17 | [0m
18 |
19 | Finished in 0.00125 seconds (files took 0.07577 seconds to load)
20 | [33m4 examples, 0 failures, 2 pending[0m
21 |
22 |
--------------------------------------------------------------------------------
/04-acceptance-specs/04/expense_tracker/spec/acceptance/expense_tracker_api_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rack/test'
2 | require 'json'
3 | require_relative '../../app/api'
4 |
5 | module ExpenseTracker
6 | RSpec.describe 'Expense Tracker API' do
7 | include Rack::Test::Methods
8 |
9 | def app
10 | ExpenseTracker::API.new
11 | end
12 |
13 | it 'records submitted expenses' do
14 | coffee = {
15 | 'payee' => 'Starbucks',
16 | 'amount' => 5.75,
17 | 'date' => '2017-06-10'
18 | }
19 |
20 | post '/expenses', JSON.generate(coffee)
21 | expect(last_response.status).to eq(200)
22 |
23 | parsed = JSON.parse(last_response.body)
24 | expect(parsed).to include('expense_id' => a_kind_of(Integer))
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/06-integration-specs/09/sessions/boot_app_success.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rackup
5 | [2017-06-13 13:34:49] INFO WEBrick 1.3.1
6 | [2017-06-13 13:34:49] INFO ruby 2.4.1 (2017-03-22) [x86_64-darwin15]
7 | [2017-06-13 13:34:49] INFO WEBrick::HTTPServer#start: pid=45924 port=9292
8 | ::1 - - [13/Jun/2017:13:34:49 -0700] "POST /expenses HTTP/1.1" 200 16 0.0090
9 | ::1 - - [13/Jun/2017:13:34:49 -0700] "POST /expenses HTTP/1.1" 200 16 0.0017
10 | ::1 - - [13/Jun/2017:13:34:49 -0700] "GET /expenses/2017-06-10 HTTP/1.1" ↩
11 | 200 120 0.0020
12 | [2017-06-13 13:34:49] INFO going to shutdown ...
13 | [2017-06-13 13:34:49] INFO WEBrick::HTTPServer#start done.
14 |
15 |
--------------------------------------------------------------------------------
/02-running-specs/08/spec/coffee_spec.rb:
--------------------------------------------------------------------------------
1 | class Coffee
2 | def ingredients
3 | @ingredients ||= []
4 | end
5 |
6 | def add(ingredient)
7 | ingredients << ingredient
8 | end
9 |
10 | def price
11 | 1.00 + ingredients.size * 0.25
12 | end
13 | end
14 |
15 | RSpec.configure do |config|
16 | config.filter_run_when_matching(focus: true)
17 | config.example_status_persistence_file_path = 'spec/examples.txt'
18 | end
19 |
20 | RSpec.describe 'A cup of coffee' do
21 | let(:coffee) { Coffee.new }
22 |
23 | it 'costs $1' do
24 | expect(coffee.price).to eq(1.00)
25 | end
26 |
27 | context 'with milk', focus: true do
28 | before { coffee.add :milk }
29 |
30 | it 'costs $1.25' do
31 | expect(coffee.price).to eq(1.25)
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/04/daily_summary_email/spec/daily_summary_spec.rb:
--------------------------------------------------------------------------------
1 | require 'daily_summary'
2 |
3 | RSpec.describe DailySummary do
4 | let(:todays_messages) do
5 | [
6 | { thread_id: 1, content: 'Hello world' },
7 | { thread_id: 2, content: 'I think forums are great' },
8 | { thread_id: 2, content: 'Me too!' }
9 | ]
10 | end
11 |
12 | it "sends a summary of today's messages and threads" do
13 | email_sender = instance_double(EmailSender)
14 | summary = DailySummary.new(email_sender: email_sender)
15 |
16 | expect(email_sender).to receive(:deliver).with(
17 | hash_including(body: 'You missed 3 messages in 2 threads today')
18 | )
19 |
20 | summary.send_daily_summary('user@example.com', todays_messages)
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/05/daily_summary_email/spec/daily_summary_spec.rb:
--------------------------------------------------------------------------------
1 | require 'daily_summary'
2 |
3 | RSpec.describe DailySummary do
4 | let(:todays_messages) do
5 | [
6 | { thread_id: 1, content: 'Hello world' },
7 | { thread_id: 2, content: 'I think forums are great' },
8 | { thread_id: 2, content: 'Me too!' }
9 | ]
10 | end
11 |
12 | it "sends a summary of today's messages and threads" do
13 | email_sender = instance_spy(EmailSender)
14 | summary = DailySummary.new(email_sender: email_sender)
15 |
16 | summary.send_daily_summary('user@example.com', todays_messages)
17 |
18 | expect(email_sender).to have_received(:deliver).with(
19 | hash_including(body: 'You missed 3 messages in 2 threads today')
20 | )
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/06-integration-specs/09/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/integration/app/ledger_spec.rb
5 |
6 | Randomized with seed 22267
7 |
8 | ExpenseTracker::Ledger
9 | #record
10 | with a valid expense
11 | [32m successfully saves the expense in the DB[0m
12 | when the expense lacks a payee
13 | [32m rejects the expense as invalid[0m
14 | #expenses_on
15 | [32m returns all expenses for the provided date[0m
16 | [32m returns a blank array when there are no matching expenses[0m
17 |
18 | Finished in 0.01832 seconds (files took 0.16797 seconds to load)
19 | [32m4 examples, 0 failures[0m
20 |
21 | Randomized with seed 22267
22 |
23 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/11/shared_examples/spec/pass_block_spec.rb:
--------------------------------------------------------------------------------
1 | RSpec.shared_examples 'KV store' do
2 | it 'allows you to fetch previously stored values' do
3 | kv_store.store(:language, 'Ruby')
4 | kv_store.store(:os, 'linux')
5 |
6 | expect(kv_store.fetch(:language)).to eq 'Ruby'
7 | expect(kv_store.fetch(:os)).to eq 'linux'
8 | end
9 |
10 | # remainder of examples...
11 |
12 | it 'raises a KeyError when you fetch an unknown key' do
13 | expect { kv_store.fetch(:foo) }.to raise_error(KeyError)
14 | end
15 | end
16 |
17 | require 'file_kv_store'
18 | require 'tempfile'
19 |
20 | RSpec.describe FileKVStore do
21 | it_behaves_like 'KV store' do
22 | let(:tempfile) { Tempfile.new('kv.store') }
23 | let(:kv_store) { FileKVStore.new(tempfile.path) }
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/exercises/phone_number_extractor_spec.rb:
--------------------------------------------------------------------------------
1 | class PhoneNumberExtractor
2 | def self.extract_from(text, &block)
3 | # Look for patterns like (###) ###-####
4 | text.scan(/(d{3}) d{3}-d{4}/, &block)
5 | end
6 | end
7 |
8 | RSpec.describe PhoneNumberExtractor do
9 | let(:text) do
10 | <<-EOS
11 | Melinda: (202) 555-0168
12 | Bob: 202-555-0199
13 | Sabina: (202) 555-0176
14 | EOS
15 | end
16 |
17 | it 'yields phone numbers as it finds them' do
18 | yielded_numbers = []
19 | PhoneNumberExtractor.extract_from(text) do |number|
20 | yielded_numbers << number
21 | end
22 |
23 | expect(yielded_numbers).to eq [
24 | '(202) 555-0168',
25 | '202-555-0199',
26 | '(202) 555-0175'
27 | ]
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/07/subscription_service/spec/recurring_payment_spec.rb:
--------------------------------------------------------------------------------
1 | require 'recurring_payment'
2 |
3 | Card = Struct.new(:type, :number)
4 | Subscription = Struct.new(:name, :credit_card, :amount)
5 |
6 | RSpec.describe RecurringPayment do
7 | it 'charges the credit card for each subscription' do
8 | card_1 = Card.new(:visa, '1234 5678 9012 3456')
9 | card_2 = Card.new(:mastercard, '9876 5432 1098 7654')
10 |
11 | subscriptions = [
12 | Subscription.new('John Doe', card_1, 19.99),
13 | Subscription.new('Jane Doe', card_2, 29.99)
14 | ]
15 |
16 | expect(CashCow).to receive(:charge_card).with(card_1, 19.99)
17 | expect(CashCow).to receive(:charge_card).with(card_2, 29.99)
18 |
19 | RecurringPayment.process_subscriptions(subscriptions)
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/02-running-specs/01/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m[31mF[0m
6 |
7 | Failures:
8 |
9 | 1) A cup of coffee with milk costs $1.25
10 | [31mFailure/Error: expect(coffee.price).to eq(1.25)[0m
11 | [31m[0m
12 | [31m expected: 1.25[0m
13 | [31m got: 1.0[0m
14 | [31m[0m
15 | [31m (compared using ==)[0m
16 | [36m# ./spec/coffee_spec.rb:26:in `block (3 levels) in '[0m
17 |
18 | Finished in 0.01222 seconds (files took 0.08094 seconds to load)
19 | [31m2 examples, 1 failure[0m
20 |
21 | Failed examples:
22 |
23 | [31mrspec ./spec/coffee_spec.rb:25[0m [36m# A cup of coffee with milk costs $1.25[0m
24 |
25 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/06/subscription_service/spec/recurring_payment_spec.rb:
--------------------------------------------------------------------------------
1 | require 'recurring_payment'
2 |
3 | Card = Struct.new(:type, :number)
4 | Subscription = Struct.new(:name, :credit_card, :amount)
5 |
6 | RSpec.describe RecurringPayment do
7 | it 'charges the credit card for each subscription' do
8 | card_1 = Card.new(:visa, '1234 5678 9012 3456')
9 | card_2 = Card.new(:mastercard, '9876 5432 1098 7654')
10 |
11 | subscriptions = [
12 | Subscription.new('John Doe', card_1, 19.99),
13 | Subscription.new('Jane Doe', card_2, 29.99)
14 | ]
15 |
16 | expect(CashCow).to receive(:charge_card).with(card_1, 19.99, :excess_arg)
17 | expect(CashCow).to receive(:charge_card).with(card_2, 29.99, :excess_arg)
18 |
19 | RecurringPayment.process_subscriptions(subscriptions)
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/06-integration-specs/07/sessions/rspec_runs/3.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | truncated
6 |
7 | Finished in 0.06926 seconds (files took 0.21812 seconds to load)
8 | [31m11 examples, 2 failures, 1 pending[0m
9 |
10 | Failed examples:
11 |
12 | [31mrspec ./spec/integration/app/ledger_spec.rb:20[0m [36m# ↩
13 | ExpenseTracker::Ledger#record with a valid expense successfully saves the ↩
14 | expense in the DB[0m
15 | [31mrspec ./spec/integration/app/ledger_spec.rb:34[0m [36m# ↩
16 | ExpenseTracker::Ledger#record when the expense lacks a payee rejects the ↩
17 | expense as invalid[0m
18 |
19 | Randomized with seed 32043
20 |
21 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/04/before_and_after_hooks_spec.rb:
--------------------------------------------------------------------------------
1 | module MyApp
2 | class Configuration
3 | end
4 | end
5 |
6 | RSpec.describe MyApp::Configuration do
7 | before(:example) do
8 | @original_env = ENV.to_hash
9 | end
10 |
11 | after(:example) do
12 | ENV.replace(@original_env)
13 | end
14 |
15 | it 'can mutate env' do
16 | ENV['FOO'] = '1'
17 | end
18 |
19 | it 'isolates mutations from other examples' do
20 | expect(ENV['FOO']).to eq nil
21 | end
22 |
23 | end
24 |
25 | class WebBrowser
26 | def self.launch; end
27 |
28 | def self.shutdown; end
29 | end
30 |
31 | RSpec.describe 'Web interface to my thermostat' do
32 | before(:context) do
33 | WebBrowser.launch
34 | end
35 |
36 | after(:context) do
37 | WebBrowser.shutdown
38 | end
39 |
40 | it 'passes' do
41 | end
42 |
43 | end
44 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/exercises/sessions/calendar_spec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec calendar_spec.rb
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) Calendar considers sundays to be on the weekend
10 | [31mFailure/Error: [0m[32mexpect[0m(sunday_date.on_weekend?).to be [1;36mtrue[0m[0m
11 | [31m[0m
12 | [31m expected true[0m
13 | [31m got false[0m
14 | [36m# ./calendar_spec.rb:13:in `block (2 levels) in '[0m
15 |
16 | Finished in 0.01342 seconds (files took 0.08792 seconds to load)
17 | [31m1 example, 1 failure[0m
18 |
19 | Failed examples:
20 |
21 | [31mrspec ./calendar_spec.rb:12[0m [36m# Calendar considers sundays to be on the weekend[0m
22 |
23 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/09/subscription_service/spec/recurring_payment_spec.rb:
--------------------------------------------------------------------------------
1 | require 'recurring_payment'
2 |
3 | Card = Struct.new(:type, :number)
4 | Subscription = Struct.new(:name, :credit_card, :amount)
5 |
6 | RSpec.describe RecurringPayment do
7 | it 'charges the credit card for each subscription' do
8 | card_1 = Card.new(:visa, '1234 5678 9012 3456')
9 | card_2 = Card.new(:mastercard, '9876 5432 1098 7654')
10 |
11 | subscriptions = [
12 | Subscription.new('John Doe', card_1, 19.99),
13 | Subscription.new('Jane Doe', card_2, 29.99)
14 | ]
15 |
16 | bank = class_double(CashCow)
17 | expect(bank).to receive(:charge_card).with(card_1, 19.99)
18 | expect(bank).to receive(:charge_card).with(card_2, 29.99)
19 |
20 | RecurringPayment.process_subscriptions(subscriptions, bank: bank)
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/02-running-specs/09/spec/coffee_spec.rb:
--------------------------------------------------------------------------------
1 | class Coffee
2 | def ingredients
3 | @ingredients ||= []
4 | end
5 |
6 | def add(ingredient)
7 | ingredients << ingredient
8 | end
9 |
10 | def price
11 | 1.00 + ingredients.size * 0.25
12 | end
13 | end
14 |
15 | RSpec.configure do |config|
16 | config.filter_run_when_matching(focus: true)
17 | config.example_status_persistence_file_path = 'spec/examples.txt'
18 | end
19 |
20 | RSpec.describe 'A cup of coffee' do
21 | let(:coffee) { Coffee.new }
22 |
23 | it 'costs $1' do
24 | expect(coffee.price).to eq(1.00)
25 | end
26 |
27 | context 'with milk' do
28 | before { coffee.add :milk }
29 |
30 | it 'costs $1.25' do
31 | expect(coffee.price).to eq(1.25)
32 | end
33 |
34 | it 'is light in color'
35 | it 'is cooler than 200 degrees Fahrenheit'
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/06-integration-specs/07/sessions/rspec_runs/4.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec --seed 32043
5 | truncated
6 |
7 | Finished in 0.05941 seconds (files took 0.22746 seconds to load)
8 | [31m11 examples, 2 failures, 1 pending[0m
9 |
10 | Failed examples:
11 |
12 | [31mrspec ./spec/integration/app/ledger_spec.rb:20[0m [36m# ↩
13 | ExpenseTracker::Ledger#record with a valid expense successfully saves the ↩
14 | expense in the DB[0m
15 | [31mrspec ./spec/integration/app/ledger_spec.rb:34[0m [36m# ↩
16 | ExpenseTracker::Ledger#record when the expense lacks a payee rejects the ↩
17 | expense as invalid[0m
18 |
19 | Randomized with seed 32043
20 |
21 |
--------------------------------------------------------------------------------
/05-unit-specs/04/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/unit/app/api_spec.rb
5 |
6 | Randomized with seed 55289
7 |
8 | ExpenseTracker::API
9 | POST /expenses
10 | when the expense is successfully recorded
11 | [32m returns the expense id[0m
12 | [32m responds with a 200 (OK)[0m
13 | when the expense fails validation
14 | [33m responds with a 422 (Unprocessable entity) (PENDING: Not yet ↩
15 | implemented)[0m
16 | [33m returns an error message (PENDING: Not yet implemented)[0m
17 |
18 | truncated
19 |
20 | Finished in 0.02565 seconds (files took 0.12232 seconds to load)
21 | [33m4 examples, 0 failures, 2 pending[0m
22 |
23 | Randomized with seed 55289
24 |
25 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/solutions/sessions/calendar_spec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec calendar_spec.rb
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) Calendar considers sundays to be on the weekend
10 | [31mFailure/Error: [0m[32mexpect[0m(sunday_date).to be_on_weekend[0m
11 | [31m expected `#.on_weekend?` to return true, got false[0m
13 | [36m# ./calendar_spec.rb:13:in `block (2 levels) in '[0m
14 |
15 | Finished in 0.01206 seconds (files took 0.07922 seconds to load)
16 | [31m1 example, 1 failure[0m
17 |
18 | Failed examples:
19 |
20 | [31mrspec ./calendar_spec.rb:12[0m [36m# Calendar considers sundays to be on the weekend[0m
21 |
22 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/solutions/public_company_spec.rb:
--------------------------------------------------------------------------------
1 | PublicCompany = Struct.new(:name, :value_per_share, :share_count) do
2 | def got_better_than_expected_revenues
3 | self.value_per_share *= rand(1.05..1.10)
4 | end
5 |
6 | def market_cap
7 | @market_cap ||= value_per_share * share_count
8 | end
9 | end
10 |
11 | RSpec.describe PublicCompany do
12 | let(:company) { PublicCompany.new('Nile', 10, 100_000) }
13 |
14 | it 'increases its market cap when it gets better than expected revenues' do
15 | expect {
16 | company.got_better_than_expected_revenues
17 | }.to change(company, :market_cap).by_at_least(50_000)
18 | end
19 |
20 | it 'provides attributes' do
21 | expect(company).to have_attributes(
22 | name: 'Nil',
23 | value_per_share: 10,
24 | share_count: 10_000,
25 | market_cap: 1_000_000
26 | )
27 | end
28 |
29 | end
30 |
--------------------------------------------------------------------------------
/02-running-specs/01/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec --format documentation
5 |
6 | A cup of coffee
7 | [32m costs $1[0m
8 | with milk
9 | [31m costs $1.25 (FAILED - 1)[0m
10 |
11 | Failures:
12 |
13 | 1) A cup of coffee with milk costs $1.25
14 | [31mFailure/Error: expect(coffee.price).to eq(1.25)[0m
15 | [31m[0m
16 | [31m expected: 1.25[0m
17 | [31m got: 1.0[0m
18 | [31m[0m
19 | [31m (compared using ==)[0m
20 | [36m# ./spec/coffee_spec.rb:26:in `block (3 levels) in '[0m
21 |
22 | Finished in 0.01073 seconds (files took 0.08736 seconds to load)
23 | [31m2 examples, 1 failure[0m
24 |
25 | Failed examples:
26 |
27 | [31mrspec ./spec/coffee_spec.rb:25[0m [36m# A cup of coffee with milk costs $1.25[0m
28 |
29 |
--------------------------------------------------------------------------------
/02-running-specs/02/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec -fd
5 |
6 | A cup of coffee
7 | [32m costs $1[0m
8 | with milk
9 | [31m costs $1.25 (FAILED - 1)[0m
10 |
11 | Failures:
12 |
13 | 1) A cup of coffee with milk costs $1.25
14 | [31mFailure/Error: [0m[32mexpect[0m(coffee.price).to eq([1;35m1.25[0m)[0m
15 | [31m[0m
16 | [31m expected: 1.25[0m
17 | [31m got: 1.0[0m
18 | [31m[0m
19 | [31m (compared using ==)[0m
20 | [36m# ./spec/coffee_spec.rb:26:in `block (3 levels) in '[0m
21 |
22 | Finished in 0.0102 seconds (files took 0.09104 seconds to load)
23 | [31m2 examples, 1 failure[0m
24 |
25 | Failed examples:
26 |
27 | [31mrspec ./spec/coffee_spec.rb:25[0m [36m# A cup of coffee with milk costs $1.25[0m
28 |
29 |
--------------------------------------------------------------------------------
/06-integration-specs/09/sessions/server_failure.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rackup
5 | [2017-06-13 13:34:47] INFO WEBrick 1.3.1
6 | [2017-06-13 13:34:47] INFO ruby 2.4.1 (2017-03-22) [x86_64-darwin15]
7 | [2017-06-13 13:34:47] INFO WEBrick::HTTPServer#start: pid=45899 port=9292
8 | 2017-06-13 13:34:47 - NameError - uninitialized constant ↩
9 | ExpenseTracker::Ledger::DB:
10 | ~/code/expense_tracker/app/ledger.rb:17:in `expenses_on'
11 | ~/code/expense_tracker/app/api.rb:25:in `block in '
12 |
13 | truncated
14 |
15 | ::1 - - [13/Jun/2017:13:34:47 -0700] "GET /expenses/2017-06-10 HTTP/1.1" ↩
16 | 500 6642 0.0019
17 | [2017-06-13 13:34:47] INFO going to shutdown ...
18 | [2017-06-13 13:34:47] INFO WEBrick::HTTPServer#start done.
19 |
20 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/exercises/guessing_game/lib/guessing_game.rb:
--------------------------------------------------------------------------------
1 | class GuessingGame
2 | def play
3 | @number = rand(1..100)
4 | @guess = nil
5 |
6 | 5.downto(1) do |remaining_guesses|
7 | break if @guess == @number
8 | puts "Pick a number 1-100 (#{remaining_guesses} guesses left):"
9 | @guess = gets.to_i
10 | check_guess
11 | end
12 |
13 | announce_result
14 | end
15 |
16 | private
17 |
18 | def check_guess
19 | if @guess > @number
20 | puts "#{@guess} is too high!"
21 | elsif @guess < @number
22 | puts "#{@guess} is too low!"
23 | end
24 | end
25 |
26 | def announce_result
27 | if @guess == @number
28 | puts 'You won!'
29 | else
30 | puts "You lost! The number was: #{@number}"
31 | end
32 | end
33 | end
34 |
35 | # play the game if this file is run directly
36 | GuessingGame.new.play if __FILE__.end_with?($PROGRAM_NAME)
37 |
--------------------------------------------------------------------------------
/05-unit-specs/02/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/unit/app/api_spec.rb
5 |
6 | Randomized with seed 34086
7 |
8 | ExpenseTracker::API
9 | POST /expenses
10 | when the expense fails validation
11 | [33m returns an error message (PENDING: Not yet implemented)[0m
12 | [33m responds with a 422 (Unprocessable entity) (PENDING: Not yet ↩
13 | implemented)[0m
14 | when the expense is successfully recorded
15 | [33m responds with a 200 (OK) (PENDING: Not yet implemented)[0m
16 | [33m returns the expense id (PENDING: Not yet implemented)[0m
17 |
18 | truncated
19 |
20 | Finished in 0.00107 seconds (files took 0.15832 seconds to load)
21 | [33m4 examples, 0 failures, 4 pending[0m
22 |
23 | Randomized with seed 34086
24 |
25 |
--------------------------------------------------------------------------------
/06-integration-specs/09/sessions/rspec_runs/3.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 |
6 | Randomized with seed 21580
7 | [31mF[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m
8 |
9 | Failures:
10 |
11 | 1) Expense Tracker API records submitted expenses FIXED
12 | [34mExpected pending 'Need to persist expenses' to fail. No error was ↩
13 | raised.[0m
14 | [36m# ./spec/acceptance/expense_tracker_api_spec.rb:22[0m
15 |
16 | Finished in 0.04844 seconds (files took 0.22185 seconds to load)
17 | [31m13 examples, 1 failure[0m
18 |
19 | Failed examples:
20 |
21 | [31mrspec ./spec/acceptance/expense_tracker_api_spec.rb:22[0m [36m# Expense Tracker ↩
22 | API records submitted expenses[0m
23 |
24 | Randomized with seed 21580
25 |
26 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/08/custom_matcher/spec/support/matchers.rb:
--------------------------------------------------------------------------------
1 | # We disable line length because the labels cause lines to be too long
2 | # but they do not render in the book so it causes no problems.
3 | RSpec::Matchers.define :have_a_balance_of do |amount|
4 | chain(:as_of) { |date| @as_of_date = date }
5 | match { |account| account_balance(account) == amount }
6 | failure_message { |account| super() + failure_reason(account) }
7 | failure_message_when_negated { |account| super() + failure_reason(account) }
8 |
9 | private
10 |
11 | def failure_reason(account)
12 | ", but had a balance of #{account_balance(account)}"
13 | end
14 |
15 | def account_balance(account)
16 | if @as_of_date
17 | account.balance_as_of(@as_of_date)
18 | else
19 | account.current_balance
20 | end
21 | end
22 | end
23 |
24 | RSpec::Matchers.alias_matcher :an_account_with_a_balance_of,
25 | :have_a_balance_of
26 |
--------------------------------------------------------------------------------
/02-running-specs/04/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec -e milk -fd
5 | Run options: include {:full_description=>/milk/}
6 |
7 | A cup of coffee
8 | with milk
9 | [31m costs $1.25 (FAILED - 1)[0m
10 |
11 | Failures:
12 |
13 | 1) A cup of coffee with milk costs $1.25
14 | [31mFailure/Error: [0m[32mexpect[0m(coffee.price).to eq([1;35m1.25[0m)[0m
15 | [31m[0m
16 | [31m expected: 1.25[0m
17 | [31m got: 1.0[0m
18 | [31m[0m
19 | [31m (compared using ==)[0m
20 | [36m# ./spec/coffee_spec.rb:26:in `block (3 levels) in '[0m
21 |
22 | Finished in 0.01014 seconds (files took 0.08249 seconds to load)
23 | [31m1 example, 1 failure[0m
24 |
25 | Failed examples:
26 |
27 | [31mrspec ./spec/coffee_spec.rb:25[0m [36m# A cup of coffee with milk costs $1.25[0m
28 |
29 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/18/twitter_user_formatter/spec/integration_spec.rb:
--------------------------------------------------------------------------------
1 | require 'twitter_user_formatter'
2 | require 'dotenv'
3 | Dotenv.load('api_creds.env')
4 |
5 | RSpec.describe TwitterUserFormatter do
6 | it 'works for real' do
7 | client = new_client do |c|
8 | c.consumer_key = ENV['TWITTER_CONSUMER_KEY']
9 | c.consumer_secret = ENV['TWITTER_CONSUMER_SECRET']
10 | c.oauth_token = ENV['TWITTER_OAUTH_TOKEN']
11 | c.oauth_token_secret = ENV['TWITTER_OAUTH_TOKEN_SECRET']
12 | end
13 |
14 | user = client.user('myronmarston')
15 | formatter = TwitterUserFormatter.new(user)
16 | expect(formatter.format).to start_with "Myron Marston's website is http"
17 | end
18 |
19 | if Twitter::Version::MAJOR == 4
20 | def new_client(&block)
21 | Twitter.configure(&block)
22 | Twitter
23 | end
24 | else
25 | def new_client(&block)
26 | Twitter::REST::Client.new(&block)
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/04-acceptance-specs/05/sessions/rspec_runs/4.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) Expense Tracker API records submitted expenses
10 | [31mFailure/Error: [0m[32mexpect[0m(expenses).to contain_exactly(coffee, zoo)[0m
11 | [31m[0m
12 | [31m expected collection contained: [{"payee"=>"Starbucks", ↩
13 | "amount"=>5.75, "date"=>"2017-06-10", "id"=>42}, {"payee"=>"Zoo", ↩
14 | "amount"=>15.25, "date"=>"2017-06-10", "id"=>42}][0m
15 | [31m actual collection contained: [][0m
16 | [31m the missing elements were: [{"payee"=>"Starbucks", ↩
17 | "amount"=>5.75, "date"=>"2017-06-10", "id"=>42}, {"payee"=>"Zoo", ↩
18 | "amount"=>15.25, "date"=>"2017-06-10", "id"=>42}][0m
19 |
20 | truncated
21 |
22 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/03/how_matchers_work.irbr:
--------------------------------------------------------------------------------
1 | >> require 'rspec/expectations'
2 | => true
3 | >> include RSpec::Matchers
4 | => Object
5 |
6 | >> matcher = Object.new
7 | => #
8 |
9 | >> expect(1).to matcher
10 | NoMethodError: undefined method `matches?' for #
11 | backtrace truncated
12 |
13 | >> def matcher.matches?(actual)
14 | >> actual == 1
15 | >> end
16 | => :matches?
17 | >> expect(1).to matcher
18 | => true
19 |
20 | >> expect(2).to matcher
21 | NoMethodError: undefined method `failure_message' for ↩
22 | #
23 | backtrace truncated
24 |
25 | >> def matcher.failure_message
26 | >> 'expected object to equal 1'
27 | >> end
28 | => :failure_message
29 | >> expect(2).to matcher
30 | RSpec::Expectations::ExpectationNotMetError: expected object to equal 1
31 | backtrace truncated
32 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/solutions/sessions/water_spec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec water_spec.rb
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) Water is H2O
10 | [31mFailure/Error: [0m[32mexpect[0m([1;34;4mWater[0m.elements).to ↩
11 | contain_exactly([33m:hydrogen[0m, [33m:hydrogen[0m, [33m:oxygen[0m)[0m
12 | [31m[0m
13 | [31m expected collection contained: [:hydrogen, :hydrogen, :oxygen][0m
14 | [31m actual collection contained: [:hydrogen, :oxygen][0m
15 | [31m the missing elements were: [:hydrogen][0m
16 | [36m# ./water_spec.rb:9:in `block (2 levels) in '[0m
17 |
18 | Finished in 0.0115 seconds (files took 0.08187 seconds to load)
19 | [31m1 example, 1 failure[0m
20 |
21 | Failed examples:
22 |
23 | [31mrspec ./water_spec.rb:8[0m [36m# Water is H2O[0m
24 |
25 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/exercises/public_company_spec.rb:
--------------------------------------------------------------------------------
1 | PublicCompany = Struct.new(:name, :value_per_share, :share_count) do
2 | def got_better_than_expected_revenues
3 | self.value_per_share *= rand(1.05..1.10)
4 | end
5 |
6 | def market_cap
7 | @market_cap ||= value_per_share * share_count
8 | end
9 | end
10 |
11 | RSpec.describe PublicCompany do
12 | let(:company) { PublicCompany.new('Nile', 10, 100_000) }
13 |
14 | it 'increases its market cap when it gets better than expected revenues' do
15 | before_market_cap = company.market_cap
16 | company.got_better_than_expected_revenues
17 | after_market_cap = company.market_cap
18 |
19 | expect(after_market_cap - before_market_cap).to be >= 50_000
20 | end
21 |
22 | it 'provides attributes' do
23 | expect(company.name).to eq('Nil')
24 | expect(company.value_per_share).to eq(10)
25 | expect(company.share_count).to eq(10_000)
26 | expect(company.market_cap).to eq(1_000_000)
27 | end
28 |
29 | end
30 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/01/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m[31mF[0m
6 |
7 | Failures:
8 |
9 | 1) PasswordStrengthValidator accepts passwords 8 characters or longer
10 | [31mFailure/Error: [0m[32mexpect[0m(validator.strong_enough?).to eq [1;36mtrue[0m[0m
11 | [31m[0m
12 | [31m expected: true[0m
13 | [31m got: false[0m
14 | [31m[0m
15 | [31m (compared using ==)[0m
16 | [36m# ./spec/password_strength_validator_spec.rb:11:in `block (2 levels) ↩
17 | in '[0m
18 |
19 | Finished in 0.01002 seconds (files took 0.08962 seconds to load)
20 | [31m2 examples, 1 failure[0m
21 |
22 | Failed examples:
23 |
24 | [31mrspec ./spec/password_strength_validator_spec.rb:9[0m [36m# ↩
25 | PasswordStrengthValidator accepts passwords 8 characters or longer[0m
26 |
27 |
--------------------------------------------------------------------------------
/06-integration-specs/09/sessions/each_spec_file_failure.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ (for f in `find spec -iname '*_spec.rb'`; do ↩
5 | echo "$f:" ↩
6 | bundle exec rspec $f -fp || exit 1 ↩
7 | done)
8 | spec/acceptance/expense_tracker_api_spec.rb:
9 |
10 | Randomized with seed 24954
11 |
12 | An error occurred in a `before(:suite)` hook.
13 | [31mFailure/Error: [0m[1;34;4mSequel[0m.extension [33m:migration[0m[0m
14 | [31m[0m
15 | [31mNameError:[0m
16 | [31m uninitialized constant Sequel[0m
17 | [36m# ./spec/support/db.rb:3:in `block (2 levels) in '[0m
18 |
19 |
20 | Finished in 0.01902 seconds (files took 0.16858 seconds to load)
21 | [31m0 examples, 0 failures, 1 error occurred outside of examples[0m
22 |
23 | Randomized with seed 24954
24 |
25 |
--------------------------------------------------------------------------------
/05-unit-specs/11/expense_tracker/spec/unit/api_example_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative '../../app/api'
2 | require 'rack/test'
3 |
4 | module ExpenseTracker
5 | RSpec.describe API do
6 | include Rack::Test::Methods
7 |
8 | def app
9 | API.new(ledger: ledger)
10 | end
11 |
12 | let(:ledger) { instance_double('ExpenseTracker::Ledger') }
13 |
14 | describe 'POST /expenses' do
15 | context 'when the expense is successfully recorded' do
16 | let(:expense) { { 'some' => 'data' } }
17 |
18 | before do
19 | allow(ledger).to receive(:record)
20 | .with(expense)
21 | .and_return(RecordResult.new(true, 417, nil))
22 | end
23 |
24 | it 'works' do
25 | post '/expenses', JSON.generate(expense)
26 |
27 | parsed = JSON.parse(last_response.body)
28 | expect(parsed).to do_something
29 | end
30 |
31 | def do_something
32 | include('expense_id' => 417)
33 | end
34 | end
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/06-integration-specs/03/expense_tracker/spec/integration/app/ledger_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative '../../../app/ledger'
2 | require_relative '../../../config/sequel'
3 | require_relative '../../support/db'
4 |
5 | module ExpenseTracker
6 | RSpec.describe Ledger do
7 | let(:ledger) { Ledger.new }
8 | let(:expense) do
9 | {
10 | 'payee' => 'Starbucks',
11 | 'amount' => 5.75,
12 | 'date' => '2017-06-10'
13 | }
14 | end
15 |
16 | describe '#record' do
17 | # ... contexts go here ...
18 |
19 | context 'with a valid expense' do
20 | it 'successfully saves the expense in the DB' do
21 | result = ledger.record(expense)
22 |
23 | expect(result).to be_success
24 | expect(DB[:expenses].all).to match [a_hash_including(
25 | id: result.expense_id,
26 | payee: 'Starbucks',
27 | amount: 5.75,
28 | date: Date.iso8601('2017-06-10')
29 | )]
30 | end
31 | end
32 |
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/06-integration-specs/01/sessions/bundle_install.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle install
5 | Fetching gem metadata from https://rubygems.org/.........
6 | Fetching version metadata from https://rubygems.org/..
7 | Resolving dependencies...
8 | Using bundler 1.15.3
9 | Using coderay 1.1.1
10 | Using diff-lcs 1.3
11 | Using mustermann 1.0.0
12 | Using rack 2.0.3
13 | Using rspec-support 3.6.0
14 | [32mFetching sequel 4.48.0[0m
15 | [32mInstalling sequel 4.48.0[0m
16 | Using tilt 2.0.7
17 | [32mFetching sqlite3 1.3.13[0m
18 | [32mInstalling sqlite3 1.3.13 with native extensions[0m
19 | Using rack-protection 2.0.0
20 | Using rack-test 0.7.0
21 | Using rspec-core 3.6.0
22 | Using rspec-expectations 3.6.0
23 | Using rspec-mocks 3.6.0
24 | Using sinatra 2.0.0
25 | Using rspec 3.6.0
26 | [32mBundle complete! 6 Gemfile dependencies, 16 gems now installed.[0m
27 | [32mUse `bundle info [gemname]` to see where a bundled gem is installed.[0m
28 |
29 |
--------------------------------------------------------------------------------
/05-unit-specs/12/sessions/rspec_runs/3.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/unit/app/api_spec.rb
5 |
6 | Randomized with seed 27973
7 |
8 | ExpenseTracker::API
9 | POST /expenses
10 | when the expense fails validation
11 | [32m responds with a 422 (Unprocessable entity)[0m
12 | [32m returns an error message[0m
13 | when the expense is successfully recorded
14 | [32m returns the expense id[0m
15 | [32m responds with a 200 (OK)[0m
16 | GET /expenses/:date
17 | when expenses exist on the given date
18 | [32m responds with a 200 (OK)[0m
19 | [32m returns the expense records as JSON[0m
20 | when there are no expenses on the given date
21 | [32m returns an empty array as JSON[0m
22 | [32m responds with a 200 (OK)[0m
23 |
24 | Finished in 0.02951 seconds (files took 0.15204 seconds to load)
25 | [32m8 examples, 0 failures[0m
26 |
27 | Randomized with seed 27973
28 |
29 |
--------------------------------------------------------------------------------
/06-integration-specs/03/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/integration/app/ledger_spec.rb
5 | truncated
6 |
7 | Failures:
8 |
9 | 1) ExpenseTracker::Ledger#record with a valid expense successfully saves ↩
10 | the expense in the DB
11 | [31mFailure/Error: [0m[32mexpect[0m(result).to be_success[0m
12 | [31m expected nil to respond to `success?`[0m
13 | [36m# ./spec/integration/app/ledger_spec.rb:23:in `block (4 levels) in ↩
14 | '[0m
15 |
16 | Finished in 0.02211 seconds (files took 0.15418 seconds to load)
17 | [31m1 example, 1 failure[0m
18 |
19 | Failed examples:
20 |
21 | [31mrspec ./spec/integration/app/ledger_spec.rb:20[0m [36m# ↩
22 | ExpenseTracker::Ledger#record with a valid expense successfully saves the ↩
23 | expense in the DB[0m
24 |
25 | Randomized with seed 27984
26 |
27 |
--------------------------------------------------------------------------------
/09-configuring-rspec/05/rspec_configure.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'rspec/core'
3 | require 'stringio'
4 |
5 | $spec_out = StringIO.new
6 | $spec_err = StringIO.new
7 | RSpec.configuration.output_stream = $spec_out
8 | RSpec.configuration.error_stream = $spec_err
9 |
10 | class SwissArmyKnife; end
11 |
12 | # Old syntax
13 |
14 | describe SwissArmyKnife do # bare `describe` method
15 | it 'is useful' do
16 | knife.should be_useful # `should` expectation
17 | end
18 | end
19 |
20 | RSpec.configure do |config|
21 | config.disable_monkey_patching!
22 | end
23 |
24 | # New syntax
25 |
26 | RSpec.describe SwissArmyKnife do # `describe` called on the `RSpec` module
27 | it 'is useful' do
28 | expect(knife).to be_useful # `expect()`-style expectation
29 | end
30 | end
31 |
32 | RSpec.configure do |config|
33 | config.order = :random
34 | end
35 |
36 | RSpec.configure do |config|
37 | config.add_setting :spec_history_api_key
38 | end
39 |
40 | RSpec.configure do |config|
41 | config.spec_history_api_key = 'a762bc901fga4b185b'
42 | end
43 |
--------------------------------------------------------------------------------
/06-integration-specs/04/expense_tracker/spec/integration/app/ledger_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative '../../../app/ledger'
2 | require_relative '../../../config/sequel'
3 | require_relative '../../support/db'
4 |
5 | module ExpenseTracker
6 | RSpec.describe Ledger do
7 | let(:ledger) { Ledger.new }
8 | let(:expense) do
9 | {
10 | 'payee' => 'Starbucks',
11 | 'amount' => 5.75,
12 | 'date' => '2017-06-10'
13 | }
14 | end
15 |
16 | describe '#record' do
17 | # ... contexts go here ...
18 |
19 | context 'with a valid expense' do
20 | it 'successfully saves the expense in the DB', :aggregate_failures do
21 | result = ledger.record(expense)
22 |
23 | expect(result).to be_success
24 | expect(DB[:expenses].all).to match [a_hash_including(
25 | id: result.expense_id,
26 | payee: 'Starbucks',
27 | amount: 5.75,
28 | date: Date.iso8601('2017-06-10')
29 | )]
30 | end
31 | end
32 |
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/06-integration-specs/05/expense_tracker/spec/integration/app/ledger_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative '../../../app/ledger'
2 | require_relative '../../../config/sequel'
3 | require_relative '../../support/db'
4 |
5 | module ExpenseTracker
6 | RSpec.describe Ledger, :aggregate_failures do
7 | let(:ledger) { Ledger.new }
8 | let(:expense) do
9 | {
10 | 'payee' => 'Starbucks',
11 | 'amount' => 5.75,
12 | 'date' => '2017-06-10'
13 | }
14 | end
15 |
16 | describe '#record' do
17 | # ... contexts go here ...
18 |
19 | context 'with a valid expense' do
20 | it 'successfully saves the expense in the DB' do
21 | result = ledger.record(expense)
22 |
23 | expect(result).to be_success
24 | expect(DB[:expenses].all).to match [a_hash_including(
25 | id: result.expense_id,
26 | payee: 'Starbucks',
27 | amount: 5.75,
28 | date: Date.iso8601('2017-06-10')
29 | )]
30 | end
31 | end
32 |
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/02-running-specs/11/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec
5 | [32m.[0m[32m.[0m[31mF[0m[31mF[0m
6 |
7 | Failures:
8 |
9 | 1) A cup of coffee with milk is light in color FIXED
10 | [34mExpected pending 'Color not implemented yet' to fail. No error was ↩
11 | raised.[0m
12 | [36m# ./spec/coffee_spec.rb:42[0m
13 |
14 | 2) A cup of coffee with milk is cooler than 200 degrees Fahrenheit FIXED
15 | [34mExpected pending 'Temperature not implemented yet' to fail. No error ↩
16 | was raised.[0m
17 | [36m# ./spec/coffee_spec.rb:47[0m
18 |
19 | Finished in 0.00293 seconds (files took 0.08214 seconds to load)
20 | [31m4 examples, 2 failures[0m
21 |
22 | Failed examples:
23 |
24 | [31mrspec ./spec/coffee_spec.rb:42[0m [36m# A cup of coffee with milk is light in color[0m
25 | [31mrspec ./spec/coffee_spec.rb:47[0m [36m# A cup of coffee with milk is cooler than ↩
26 | 200 degrees Fahrenheit[0m
27 |
28 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/05/custom_matchers.irbr:
--------------------------------------------------------------------------------
1 | >> require 'rspec/expectations'
2 | => true
3 | >> include RSpec::Matchers
4 | => Object
5 |
6 | >> RSpec::Matchers.alias_matcher :an_admin, :be_an_admin
7 | => :an_admin
8 |
9 | >> be_an_admin.description
10 | => "be an admin"
11 | >> an_admin.description
12 | => "an admin"
13 |
14 | >> RSpec::Matchers.alias_matcher :an_admin, :be_an_admin do |old_description|
15 | >> old_description.sub('be an admin', 'a superuser')
16 | >> end
17 | => :an_admin
18 |
19 | >> an_admin.description
20 | => "a superuser"
21 |
22 | >> adverb = 'absolutely'
23 | => "absolutely"
24 |
25 | >> expect(adverb).not_to start_with('a').and end_with('z')
26 | NotImplementedError: `expect(...).not_to matcher.and matcher` is not ↩
27 | supported, since it creates a bit of an ambiguity. Instead, define negated ↩
28 | versions of whatever matchers you wish to negate with ↩
29 | `RSpec::Matchers.define_negated_matcher` and use `expect(...).to ↩
30 | matcher.and matcher`.
31 | backtrace truncated
32 |
--------------------------------------------------------------------------------
/02-running-specs/10/spec/coffee_spec.rb:
--------------------------------------------------------------------------------
1 | class Coffee
2 | def ingredients
3 | @ingredients ||= []
4 | end
5 |
6 | def add(ingredient)
7 | ingredients << ingredient
8 | end
9 |
10 | def price
11 | 1.00 + ingredients.size * 0.25
12 | end
13 | end
14 |
15 | RSpec.configure do |config|
16 | config.filter_run_when_matching(focus: true)
17 | config.example_status_persistence_file_path = 'spec/examples.txt'
18 | end
19 |
20 | RSpec.describe 'A cup of coffee' do
21 | let(:coffee) { Coffee.new }
22 |
23 | it 'costs $1' do
24 | expect(coffee.price).to eq(1.00)
25 | end
26 |
27 | context 'with milk' do
28 | before { coffee.add :milk }
29 |
30 | it 'costs $1.25' do
31 | expect(coffee.price).to eq(1.25)
32 | end
33 |
34 | it 'is light in color' do
35 | pending 'Color not implemented yet'
36 | expect(coffee.color).to be(:light)
37 | end
38 |
39 | it 'is cooler than 200 degrees Fahrenheit' do
40 | pending 'Temperature not implemented yet'
41 | expect(coffee.temperature).to be < 200.0
42 | end
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/08/custom_matcher/spec/as_of_account_spec.rb:
--------------------------------------------------------------------------------
1 | require 'account'
2 | require 'support/matchers'
3 |
4 | RSpec.describe '`have_a_balance_of(amount)`' do
5 | let(:account) { Account.new('Checking') }
6 |
7 | before do
8 | account.expenses << Expense.new(Date.new(2017, 6, 10), 10)
9 | account.expenses << Expense.new(Date.new(2017, 6, 15), 20)
10 | end
11 |
12 | it 'passes when the balances match' do
13 | expect(account).to have_a_balance_of(30)
14 | # or
15 | expect(account).to have_a_balance_of(10).as_of(Date.new(2017, 6, 12))
16 | end
17 |
18 | it "fails when a date's balance does not match" do
19 | expect(account).to have_a_balance_of(15).as_of(Date.new(2017, 6, 12))
20 | end
21 |
22 | it 'can be used in a compound expression' do
23 | expect(account).to have_a_balance_of(30).and \
24 | have_attributes(name: 'Checking')
25 | end
26 |
27 | it 'can be passed to another matcher' do
28 | user_accounts = [account]
29 |
30 | expect(user_accounts).to include(an_account_with_a_balance_of(30))
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/06-integration-specs/07/sessions/rspec_runs/5.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec --bisect --seed 32043
5 | Bisect started using options: "--seed 32043"
6 | Running suite to find failures... (0.45293 seconds)
7 | Starting bisect with 2 failing examples and 9 non-failing examples.
8 | Checking that failure(s) are order-dependent... failure appears to be ↩
9 | order-dependent
10 |
11 | Round 1: bisecting over non-failing examples 1-9 . ignoring examples 1-5 ↩
12 | (0.45132 seconds)
13 | Round 2: bisecting over non-failing examples 6-9 . ignoring examples 6-7 ↩
14 | (0.43739 seconds)
15 | Round 3: bisecting over non-failing examples 8-9 . ignoring example 8 ↩
16 | (0.43102 seconds)
17 | Bisect complete! Reduced necessary non-failing examples from 9 to 1 in 1.64 ↩
18 | seconds.
19 |
20 | The minimal reproduction command is:
21 | rspec './spec/acceptance/expense_tracker_api_spec.rb[1:1]' ↩
22 | './spec/integration/app/ledger_spec.rb[1:1:1:1,1:1:2:1]' --seed 32043
23 |
24 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/06/transit/spec/berlin_transit_ticket_spec.rb:
--------------------------------------------------------------------------------
1 | require 'berlin_transit_ticket'
2 |
3 | # We disable line length because the labels cause lines to be too long
4 | # but they do not render in the book so it causes no problems.
5 | RSpec.describe BerlinTransitTicket do
6 | let(:ticket) { BerlinTransitTicket.new }
7 |
8 | before do
9 | # These values depend on `let` definitions
10 | # defined in the nested contexts below!
11 | #
12 | ticket.starting_station = starting_station
13 | ticket.ending_station = ending_station
14 | end
15 |
16 | let(:fare) { ticket.fare }
17 |
18 | context 'when starting in zone A' do
19 | let(:starting_station) { 'Bundestag' }
20 |
21 | context 'and ending in zone B' do
22 | let(:ending_station) { 'Leopoldplatz' }
23 |
24 | it 'costs €2.70' do
25 | expect(fare).to eq 2.7
26 | end
27 | end
28 |
29 | context 'and ending in zone C' do
30 | let(:ending_station) { 'Birkenwerder' }
31 |
32 | it 'costs €3.30' do
33 | expect(fare).to eq 3.3
34 | end
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/09/custom_matcher/spec/support/matchers.rb:
--------------------------------------------------------------------------------
1 | # We disable line length because the labels cause lines to be too long
2 | # but they do not render in the book so it causes no problems.
3 | RSpec::Matchers.define :have_a_balance_of do |amount|
4 | chain(:as_of) { |date| @as_of_date = date }
5 | match do |account|
6 | values_match?(amount, account_balance(account))
7 |
8 | account_balance(account) == account
9 | end
10 |
11 | match { |account| values_match?(amount, account_balance(account)) }
12 | failure_message { |account| super() + failure_reason(account) }
13 | failure_message_when_negated { |account| super() + failure_reason(account) }
14 |
15 | private
16 |
17 | def failure_reason(account)
18 | ", but had a balance of #{account_balance(account)}"
19 | end
20 |
21 | def account_balance(account)
22 | if @as_of_date
23 | account.balance_as_of(@as_of_date)
24 | else
25 | account.current_balance
26 | end
27 | end
28 | end
29 |
30 | RSpec::Matchers.alias_matcher :an_account_with_a_balance_of,
31 | :have_a_balance_of
32 |
--------------------------------------------------------------------------------
/15-using-test-doubles-effectively/solutions/guessing_game/lib/guessing_game.rb:
--------------------------------------------------------------------------------
1 | class GuessingGame
2 | def initialize(input: $stdin, output: $stdout, random: Random.new)
3 | @input, @output, @random = input, output, random
4 | @number = random.rand(1..100)
5 | @guess = nil
6 | end
7 |
8 | def play
9 | 5.downto(1) do |remaining_guesses|
10 | break if @guess == @number
11 | @output.puts "Pick a number 1-100 (#{remaining_guesses} guesses left):"
12 | @guess = @input.gets.to_i
13 | check_guess
14 | end
15 |
16 | announce_result
17 | end
18 |
19 | private
20 |
21 | def check_guess
22 | if @guess > @number
23 | @output.puts "#{@guess} is too high!"
24 | elsif @guess < @number
25 | @output.puts "#{@guess} is too low!"
26 | end
27 | end
28 |
29 | def announce_result
30 | if @guess == @number
31 | @output.puts 'You won!'
32 | else
33 | @output.puts "You lost! The number was: #{@number}"
34 | end
35 | end
36 | end
37 |
38 | # play the game if this file is run directly
39 | GuessingGame.new.play if __FILE__.end_with?($PROGRAM_NAME)
40 |
--------------------------------------------------------------------------------
/05-unit-specs/03/expense_tracker/api_snippets.rb:
--------------------------------------------------------------------------------
1 | # Load the spec so we get access to `RecordResult` struct.
2 | require 'rspec/core'
3 | require_relative 'spec/unit/app/api_spec.rb'
4 | require 'sinatra/base'
5 |
6 | class Ledger
7 | def record(_expense)
8 | ExpenseTracker::RecordResult.new
9 | end
10 | end
11 |
12 | class API < Sinatra::Base
13 | def initialize
14 | @ledger = Ledger.new
15 | super() # rest of initialization from Sinatra
16 | end
17 | end
18 |
19 | # Later, callers do this:
20 | app = API.new
21 | app.to_s # avoid unused variable warning
22 |
23 | Object.send(:remove_const, :API)
24 |
25 | class API < Sinatra::Base
26 | def initialize(ledger:)
27 | @ledger = ledger
28 | super()
29 | end
30 | end
31 |
32 | # Later, callers do this:
33 | app = API.new(ledger: Ledger.new)
34 | app.to_s # avoid unused variable warning
35 |
36 | @ledger = Ledger.new
37 |
38 | # Pseudocode for what happens inside the API class:
39 | #
40 | result = @ledger.record({ 'some' => 'data' })
41 | result.success? # => a Boolean
42 | result.expense_id # => a number
43 | result.error_message # => a string or nil
44 |
--------------------------------------------------------------------------------
/05-unit-specs/04/sessions/rspec_runs/2.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/unit/app/api_spec.rb
5 | truncated
6 |
7 | Failures:
8 |
9 | 1) ExpenseTracker::API POST /expenses when the expense is successfully ↩
10 | recorded responds with a 200 (OK)
11 | [31mFailure/Error: [0m[32mexpect[0m(last_response.status).to eq([1;34m200[0m)[0m
12 | [31m[0m
13 | [31m expected: 200[0m
14 | [31m got: 404[0m
15 | [31m[0m
16 | [31m (compared using ==)[0m
17 | [36m# ./spec/unit/app/api_spec.rb:41:in `block (4 levels) in ↩
18 | '[0m
19 |
20 | Finished in 0.03479 seconds (files took 0.14115 seconds to load)
21 | [31m4 examples, 1 failure, 2 pending[0m
22 |
23 | Failed examples:
24 |
25 | [31mrspec ./spec/unit/app/api_spec.rb:33[0m [36m# ExpenseTracker::API POST /expenses ↩
26 | when the expense is successfully recorded responds with a 200 (OK)[0m
27 |
28 | Randomized with seed 32399
29 |
30 |
--------------------------------------------------------------------------------
/14-customizing-test-doubles/02/stock_ticker.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'timeout'
3 |
4 | class StockTicker
5 | attr_reader :nasdaq_client
6 |
7 | def initialize(nasdaq_client)
8 | @nasdaq_client = nasdaq_client
9 | @error_count = 0
10 | end
11 |
12 | def price(stock_name)
13 | return nil if @error_count >= 3
14 | nasdaq_client.current_price(stock_name)
15 | rescue Timeout::Error
16 | @error_count += 1
17 | nil
18 | end
19 |
20 | def inspect
21 | '#'
22 | end
23 | end
24 |
25 | require 'rspec/mocks/standalone'
26 |
27 | client = instance_double('NasdaqClient')
28 | expect(client).to receive(:current_price).thrice.and_raise(Timeout::Error)
29 | stock_ticker = StockTicker.new(client)
30 | 100.times { stock_ticker.price('AAPL') }
31 |
32 | RSpec::Mocks.verify
33 |
34 | expect(client).to receive(:current_price).exactly(4).times
35 |
36 | expect(client).to receive(:current_price).at_least(3).times
37 | expect(client).to receive(:current_price).at_most(10).times
38 |
39 | expect(client).to receive(:current_price).at_least(:once)
40 | expect(client).to receive(:current_price).at_most(:thrice)
41 |
--------------------------------------------------------------------------------
/07-structuring-code-examples/03/expense_tracker/spec/api_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative '../app/api'
2 | require 'rack/test'
3 |
4 | # This spec file contains a condensed form of `spec/unit/api_spec.rb` for the
5 | # purpose of showing the constructs to share setup logic in ch 7.
6 |
7 | module ExpenseTracker
8 | RSpec.describe 'POST a successful expense' do
9 | # let definitions
10 | let(:ledger) { instance_double('ExpenseTracker::Ledger') }
11 | let(:expense) { { 'some' => 'data' } }
12 |
13 | # hook
14 | before do
15 | allow(ledger).to receive(:record)
16 | .with(expense)
17 | .and_return(RecordResult.new(true, 417, nil))
18 | end
19 |
20 | # helper method
21 | def parsed_last_response
22 | JSON.parse(last_response.body)
23 | end
24 |
25 | include Rack::Test::Methods
26 |
27 | def app
28 | API.new(ledger: ledger)
29 | end
30 |
31 | it 'responds with a 200 (OK)' do
32 | post '/expenses', JSON.generate(expense)
33 | expect(last_response.status).to eq(200)
34 | expect(parsed_last_response).to include('expense_id' => 417)
35 | end
36 |
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/09-configuring-rspec/02/configuring_rspec/rspec/print_failures_eagerly.rb:
--------------------------------------------------------------------------------
1 | require 'rspec/core'
2 | require 'rspec/core/formatters/base_text_formatter'
3 | require 'rspec/print_failures_eagerly/version'
4 |
5 | # We disable line length because the labels cause lines to be too long
6 | # but they do not render in the book so it causes no problems.
7 | module RSpec
8 | module PrintFailuresEagerly
9 | class Formatter
10 | RSpec::Core::Formatters.register self, :example_failed
11 |
12 | def initialize(output)
13 | @output = output
14 | @last_failure_index = 0
15 | end
16 |
17 | def example_failed(notification)
18 | @output.puts
19 | @output.puts notification.fully_formatted(@last_failure_index += 1)
20 | @output.puts
21 | end
22 | end
23 | module SilenceDumpFailures
24 | def dump_failures(_notification)
25 | end
26 |
27 | RSpec::Core::Formatters::BaseTextFormatter.prepend(self)
28 | end
29 | end
30 | end
31 |
32 | RSpec.configure do |config|
33 | config.before(:suite) do
34 | config.add_formatter RSpec::PrintFailuresEagerly::Formatter
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/exercises/sessions/water_spec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec water_spec.rb
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) Water is H2O
10 | [31mFailure/Error: [0m[32mexpect[0m([1;34;4mWater[0m.elements.sort).to eq [[33m:hydrogen[0m, ↩
11 | [33m:hydrogen[0m, [33m:oxygen[0m][0m
12 | [31m[0m
13 | [31m expected: [:hydrogen, :hydrogen, :oxygen][0m
14 | [31m got: [:hydrogen, :oxygen][0m
15 | [31m[0m
16 | [31m (compared using ==)[0m
17 | [31m[0m
18 | [31m Diff:[0m[0m
19 | [31m [0m[34m@@ -1,2 +1,2 @@[0m
20 | [31m [0m[31m-[:hydrogen, :hydrogen, :oxygen][0m
21 | [31m [0m[32m+[:hydrogen, :oxygen][0m
22 | [31m [0m[0m
23 | [36m# ./water_spec.rb:9:in `block (2 levels) in '[0m
24 |
25 | Finished in 0.01163 seconds (files took 0.08126 seconds to load)
26 | [31m1 example, 1 failure[0m
27 |
28 | Failed examples:
29 |
30 | [31mrspec ./water_spec.rb:8[0m [36m# Water is H2O[0m
31 |
32 |
--------------------------------------------------------------------------------
/10-exploring-rspec-expectations/04/composing_matchers.rb:
--------------------------------------------------------------------------------
1 | # validate me
2 | require 'rspec/expectations'
3 | include RSpec::Matchers
4 |
5 | presidents = [
6 | { name: 'George Washington', birth_year: 1732 },
7 | { name: 'John Adams', birth_year: 1735 },
8 | { name: 'Thomas Jefferson', birth_year: 1743 },
9 | # ...
10 | ]
11 | expect(presidents).to start_with(
12 | { name: 'George Washington', birth_year: a_value_between(1730, 1740) },
13 | { name: 'John Adams', birth_year: a_value_between(1730, 1740) }
14 | )
15 |
16 | alphabet = ('a'..'z').to_a
17 | expect(alphabet).to start_with('a').and end_with('z')
18 |
19 | stoplight_color = %w[ green red yellow ].sample
20 | expect(stoplight_color).to eq('green').or eq('red').or eq('yellow')
21 |
22 | alphabet = ('a'..'z').to_a
23 | expect(alphabet).to start_with('a') & end_with('z')
24 |
25 | stoplight_color = %w[ green red yellow ].sample
26 | expect(stoplight_color).to eq('green') | eq('red') | eq('yellow')
27 |
28 | letter_ranges = ['N to Z', 'A to M']
29 | expect(letter_ranges).to contain_exactly(
30 | a_string_starting_with('A') & ending_with('M'),
31 | a_string_starting_with('N') & ending_with('Z')
32 | )
33 |
--------------------------------------------------------------------------------
/04-acceptance-specs/01/sessions/bundle_install.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle install
5 | Fetching gem metadata from https://rubygems.org/.........
6 | Fetching version metadata from https://rubygems.org/..
7 | Resolving dependencies...
8 | Using bundler 1.15.3
9 | Using coderay 1.1.1
10 | Using diff-lcs 1.3
11 | [32mFetching mustermann 1.0.0[0m
12 | [32mInstalling mustermann 1.0.0[0m
13 | [32mFetching rack 2.0.3[0m
14 | [32mInstalling rack 2.0.3[0m
15 | Using rspec-support 3.6.0
16 | [32mFetching tilt 2.0.7[0m
17 | [32mInstalling tilt 2.0.7[0m
18 | [32mFetching rack-protection 2.0.0[0m
19 | [32mInstalling rack-protection 2.0.0[0m
20 | [32mFetching rack-test 0.7.0[0m
21 | [32mInstalling rack-test 0.7.0[0m
22 | Using rspec-core 3.6.0
23 | Using rspec-expectations 3.6.0
24 | Using rspec-mocks 3.6.0
25 | [32mFetching sinatra 2.0.0[0m
26 | [32mInstalling sinatra 2.0.0[0m
27 | Using rspec 3.6.0
28 | [32mBundle complete! 4 Gemfile dependencies, 14 gems now installed.[0m
29 | [32mUse `bundle info [gemname]` to see where a bundled gem is installed.[0m
30 |
31 |
--------------------------------------------------------------------------------
/06-integration-specs/07/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/integration/app/ledger_spec.rb
5 | truncated
6 |
7 | Failures:
8 |
9 | 1) ExpenseTracker::Ledger#record when the expense lacks a payee rejects ↩
10 | the expense as invalid
11 |
12 | truncated
13 |
14 | 2) ExpenseTracker::Ledger#record with a valid expense successfully saves ↩
15 | the expense in the DB
16 |
17 | truncated
18 |
19 | Finished in 0.02597 seconds (files took 0.18213 seconds to load)
20 | [31m2 examples, 2 failures[0m
21 |
22 | Failed examples:
23 |
24 | [31mrspec ./spec/integration/app/ledger_spec.rb:34[0m [36m# ↩
25 | ExpenseTracker::Ledger#record when the expense lacks a payee rejects the ↩
26 | expense as invalid[0m
27 | [31mrspec ./spec/integration/app/ledger_spec.rb:20[0m [36m# ↩
28 | ExpenseTracker::Ledger#record with a valid expense successfully saves the ↩
29 | expense in the DB[0m
30 |
31 | Randomized with seed 57045
32 |
33 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/solutions/sessions/tokenizer_spec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec tokenizer_spec.rb
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) Tokenizer tokenizes multiple lines of text
10 | [31mFailure/Error: [0m[32mexpect[0m(tokenized).to start_with([31m[1;31m'[0m[31mI[1;31m'[0m[31m[0m, [31m[1;31m'[0m[31mam[1;31m'[0m[31m[0m, [31m[1;31m'[0m[31mSam.[1;31m'[0m[31m[0m, ↩
11 | [31m[1;31m'[0m[31mSam[1;31m'[0m[31m[0m, [31m[1;31m'[0m[31mI[1;31m'[0m[31m[0m, [31m[1;31m'[0m[31mam[1;31m'[0m[31m[0m)[0m
12 | [31m expected ["", "I", "am", "Sam.\n", "Sam", "I", "am.\n", "Do", "you", ↩
13 | "like", "green", "eggs", "and", "ham?\n"] to start with "I", "am", ↩
14 | "Sam.", "Sam", "I", and "am"[0m
15 | [36m# ./tokenizer_spec.rb:18:in `block (2 levels) in '[0m
16 |
17 | Finished in 0.01074 seconds (files took 0.07581 seconds to load)
18 | [31m1 example, 1 failure[0m
19 |
20 | Failed examples:
21 |
22 | [31mrspec ./tokenizer_spec.rb:16[0m [36m# Tokenizer tokenizes multiple lines of text[0m
23 |
24 |
--------------------------------------------------------------------------------
/08-metadata/01/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec spec/metadata_spec.rb
5 | {:block=>
6 | #,
7 | :description_args=>["is used by RSpec for metadata"],
8 | :description=>"is used by RSpec for metadata",
9 | :full_description=>"Hash is used by RSpec for metadata",
10 | :described_class=>Hash,
11 | :file_path=>"./spec/metadata_spec.rb",
12 | :line_number=>4,
13 | :location=>"./spec/metadata_spec.rb:4",
14 | :absolute_file_path=>
15 | "~/code/metadata/spec/metadata_spec.rb",
16 | :rerun_file_path=>"./spec/metadata_spec.rb",
17 | :scoped_id=>"1:1",
18 | :execution_result=>
19 | #,
21 | :example_group=>
22 | {:block=>
23 | #,
24 |
25 | truncated
26 |
27 | :shared_group_inclusion_backtrace=>[],
28 | :last_run_status=>"unknown"}
29 | [32m.[0m
30 |
31 | Finished in 0.00279 seconds (files took 0.09431 seconds to load)
32 | [32m1 example, 0 failures[0m
33 |
34 |
--------------------------------------------------------------------------------
/02-running-specs/11/spec/coffee_spec.rb:
--------------------------------------------------------------------------------
1 | class Coffee
2 | def ingredients
3 | @ingredients ||= []
4 | end
5 |
6 | def add(ingredient)
7 | ingredients << ingredient
8 | end
9 |
10 | def price
11 | 1.00 + ingredients.size * 0.25
12 | end
13 |
14 | def color
15 | ingredients.include?(:milk) ? :light : :dark
16 | end
17 |
18 | def temperature
19 | ingredients.include?(:milk) ? 190.0 : 205.0
20 | end
21 | end
22 |
23 | RSpec.configure do |config|
24 | config.filter_run_when_matching(focus: true)
25 | config.example_status_persistence_file_path = 'spec/examples.txt'
26 | end
27 |
28 | RSpec.describe 'A cup of coffee' do
29 | let(:coffee) { Coffee.new }
30 |
31 | it 'costs $1' do
32 | expect(coffee.price).to eq(1.00)
33 | end
34 |
35 | context 'with milk' do
36 | before { coffee.add :milk }
37 |
38 | it 'costs $1.25' do
39 | expect(coffee.price).to eq(1.25)
40 | end
41 |
42 | it 'is light in color' do
43 | pending 'Color not implemented yet'
44 | expect(coffee.color).to be(:light)
45 | end
46 |
47 | it 'is cooler than 200 degrees Fahrenheit' do
48 | pending 'Temperature not implemented yet'
49 | expect(coffee.temperature).to be < 200.0
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/06-integration-specs/09/sessions/each_spec_file_success.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ (for f in `find spec -iname '*_spec.rb'`; do ↩
5 | echo "$f:" ↩
6 | bundle exec rspec $f -fp || exit 1 ↩
7 | done)
8 | spec/acceptance/expense_tracker_api_spec.rb:
9 |
10 | Randomized with seed 64689
11 | [32m.[0m
12 |
13 | Finished in 0.02758 seconds (files took 0.20933 seconds to load)
14 | [32m1 example, 0 failures[0m
15 |
16 | Randomized with seed 64689
17 |
18 | spec/integration/app/ledger_spec.rb:
19 |
20 | Randomized with seed 7247
21 | [32m.[0m[32m.[0m[32m.[0m[32m.[0m
22 |
23 | Finished in 0.01689 seconds (files took 0.15956 seconds to load)
24 | [32m4 examples, 0 failures[0m
25 |
26 | Randomized with seed 7247
27 |
28 | spec/unit/app/api_spec.rb:
29 |
30 | Randomized with seed 21495
31 | [32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m
32 |
33 | Finished in 0.02619 seconds (files took 0.21264 seconds to load)
34 | [32m8 examples, 0 failures[0m
35 |
36 | Randomized with seed 21495
37 |
38 |
--------------------------------------------------------------------------------
/12-creating-custom-matchers/exercises/custom_matcher/spec/event_matchers_spec.rb:
--------------------------------------------------------------------------------
1 | Event = Struct.new(:name, :capacity) do
2 | def purchase_ticket_for(guest)
3 | tickets_sold << guest
4 | end
5 |
6 | def tickets_sold
7 | @tickets_sold ||= []
8 | end
9 |
10 | def inspect
11 | "#"
12 | end
13 | end
14 |
15 | RSpec.describe '`have_no_tickets_sold` matcher' do
16 | example 'passing expectation' do
17 | art_show = Event.new('Art Show', 100)
18 |
19 | expect(art_show).to have_no_tickets_sold
20 | end
21 |
22 | example 'failing expectation' do
23 | art_show = Event.new('Art Show', 100)
24 | art_show.purchase_ticket_for(:a_friend)
25 |
26 | expect(art_show).to have_no_tickets_sold
27 | end
28 | end
29 |
30 | RSpec.describe '`be_sold_out` matcher' do
31 | example 'passing expectation' do
32 | u2_concert = Event.new('U2 Concert', 10_000)
33 | 10_000.times { u2_concert.purchase_ticket_for(:a_fan) }
34 |
35 | expect(u2_concert).to be_sold_out
36 | end
37 |
38 | example 'failing expectation' do
39 | u2_concert = Event.new('U2 Concert', 10_000)
40 | 9_900.times { u2_concert.purchase_ticket_for(:a_fan) }
41 |
42 | expect(u2_concert).to be_sold_out
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/06-integration-specs/07/sessions/rspec_runs/6.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec './spec/acceptance/expense_tracker_api_spec.rb[1:1]' ↩
5 | './spec/integration/app/ledger_spec.rb[1:1:1:1,1:1:2:1]' --seed 32043
6 | Run options: include ↩
7 | {:ids=>{"./spec/acceptance/expense_tracker_api_spec.rb"=>["1:1"], ↩
8 | "./spec/integration/app/ledger_spec.rb"=>["1:1:1:1", "1:1:2:1"]}}
9 |
10 | Randomized with seed 32043
11 | [33m*[0m[31mF[0m[31mF[0m
12 |
13 | truncated
14 |
15 | Finished in 0.0485 seconds (files took 0.21859 seconds to load)
16 | [31m3 examples, 2 failures, 1 pending[0m
17 |
18 | Failed examples:
19 |
20 | [31mrspec ./spec/integration/app/ledger_spec.rb:20[0m [36m# ↩
21 | ExpenseTracker::Ledger#record with a valid expense successfully saves the ↩
22 | expense in the DB[0m
23 | [31mrspec ./spec/integration/app/ledger_spec.rb:34[0m [36m# ↩
24 | ExpenseTracker::Ledger#record when the expense lacks a payee rejects the ↩
25 | expense as invalid[0m
26 |
27 | Randomized with seed 32043
28 |
29 |
--------------------------------------------------------------------------------
/04-acceptance-specs/06/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec
5 | [33m*[0m
6 |
7 | Pending: (Failures listed here are expected and do not affect your suite's ↩
8 | status)
9 |
10 | 1) Expense Tracker API records submitted expenses
11 | [36m# Need to persist expenses[0m
12 | [33mFailure/Error: [0m[32mexpect[0m(expenses).to contain_exactly(coffee, zoo)[0m
13 | [33m[0m
14 | [33m expected collection contained: [{"payee"=>"Starbucks", ↩
15 | "amount"=>5.75, "date"=>"2017-06-10", "id"=>42}, {"payee"=>"Zoo", ↩
16 | "amount"=>15.25, "date"=>"2017-06-10", "id"=>42}][0m
17 | [33m actual collection contained: [][0m
18 | [33m the missing elements were: [{"payee"=>"Starbucks", ↩
19 | "amount"=>5.75, "date"=>"2017-06-10", "id"=>42}, {"payee"=>"Zoo", ↩
20 | "amount"=>15.25, "date"=>"2017-06-10", "id"=>42}][0m
21 | [36m# ./spec/acceptance/expense_tracker_api_spec.rb:46:in `block (2 ↩
22 | levels) in '[0m
23 |
24 | Finished in 0.03437 seconds (files took 0.1271 seconds to load)
25 | [33m1 example, 0 failures, 1 pending[0m
26 |
27 |
--------------------------------------------------------------------------------
/05-unit-specs/03/expense_tracker/spec/unit/app/api_spec.rb:
--------------------------------------------------------------------------------
1 | require_relative '../../../app/api'
2 | require 'rack/test'
3 |
4 | module ExpenseTracker
5 | RecordResult = Struct.new(:success?, :expense_id, :error_message)
6 |
7 | RSpec.describe API do
8 | include Rack::Test::Methods
9 |
10 | def app
11 | API.new(ledger: ledger)
12 | end
13 |
14 | let(:ledger) { instance_double('ExpenseTracker::Ledger') }
15 |
16 | describe 'POST /expenses' do
17 | context 'when the expense is successfully recorded' do
18 | # ... specs go here ...
19 |
20 | it 'returns the expense id' do
21 | expense = { 'some' => 'data' }
22 |
23 | allow(ledger).to receive(:record)
24 | .with(expense)
25 | .and_return(RecordResult.new(true, 417, nil))
26 |
27 | post '/expenses', JSON.generate(expense)
28 |
29 | parsed = JSON.parse(last_response.body)
30 | expect(parsed).to include('expense_id' => 417)
31 | end
32 |
33 | it 'responds with a 200 (OK)'
34 | end
35 |
36 | context 'when the expense fails validation' do
37 | # ... specs go here ...
38 | it 'returns an error message'
39 | it 'responds with a 422 (Unprocessable entity)'
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/11-matchers-included-in-rspec-expectations/exercises/sessions/phone_number_extractor_spec.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec phone_number_extractor_spec.rb
5 | [31mF[0m
6 |
7 | Failures:
8 |
9 | 1) PhoneNumberExtractor yields phone numbers as it finds them
10 | [31mFailure/Error:[0m
11 | [31m [0m[32mexpect[0m(yielded_numbers).to eq [[0m
12 | [31m [0m[31m[1;31m'[0m[31m(202) 555-0168[1;31m'[0m[31m[0m,[0m
13 | [31m [0m[31m[1;31m'[0m[31m202-555-0199[1;31m'[0m[31m[0m,[0m
14 | [31m [0m[31m[1;31m'[0m[31m(202) 555-0175[1;31m'[0m[31m[0m[0m
15 | [31m [0m][0m
16 | [31m[0m
17 | [31m expected: ["(202) 555-0168", "202-555-0199", "(202) 555-0175"][0m
18 | [31m got: [][0m
19 | [31m[0m
20 | [31m (compared using ==)[0m
21 | [36m# ./phone_number_extractor_spec.rb:23:in `block (2 levels) in '[0m
23 |
24 | Finished in 0.00956 seconds (files took 0.08245 seconds to load)
25 | [31m1 example, 1 failure[0m
26 |
27 | Failed examples:
28 |
29 | [31mrspec ./phone_number_extractor_spec.rb:17[0m [36m# PhoneNumberExtractor yields ↩
30 | phone numbers as it finds them[0m
31 |
32 |
--------------------------------------------------------------------------------
/05-unit-specs/03/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ bundle exec rspec spec/unit/app/api_spec.rb
5 | truncated
6 |
7 | Failures:
8 |
9 | 1) ExpenseTracker::API POST /expenses when the expense is successfully ↩
10 | recorded returns the expense id
11 | [31mFailure/Error: [0m[32mexpect[0m(parsed).to include([31m[1;31m'[0m[31mexpense_id[1;31m'[0m[31m[0m => [1;34m417[0m)[0m
12 | [31m[0m
13 | [31m expected {"expense_id" => 42} to include {"expense_id" => 417}[0m
14 | [31m Diff:[0m[0m
15 | [31m [0m[34m@@ -1,2 +1,2 @@[0m
16 | [31m [0m[31m-"expense_id" => 417,[0m
17 | [31m [0m[32m+"expense_id" => 42,[0m
18 | [31m [0m[0m
19 | [36m# ./spec/unit/app/api_spec.rb:30:in `block (4 levels) in ↩
20 | '[0m
21 |
22 | Finished in 0.03784 seconds (files took 0.16365 seconds to load)
23 | [31m4 examples, 1 failure, 3 pending[0m
24 |
25 | Failed examples:
26 |
27 | [31mrspec ./spec/unit/app/api_spec.rb:20[0m [36m# ExpenseTracker::API POST /expenses ↩
28 | when the expense is successfully recorded returns the expense id[0m
29 |
30 | Randomized with seed 56373
31 |
32 |
--------------------------------------------------------------------------------
/09-configuring-rspec/02/sessions/rspec_runs/1.pml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $ rspec a_spec.rb
5 | [31mF[0m
6 |
7 | 1) A group with a failure has an example that fails
8 | [31mFailure/Error: [0m[32mexpect[0m([1;34m1[0m).to eq [1;34m2[0m[0m
9 | [31m[0m
10 | [31m expected: 2[0m
11 | [31m got: 1[0m
12 | [31m[0m
13 | [31m (compared using ==)[0m
14 | [36m# ./a_spec.rb:3:in `block (2 levels) in '[0m
15 |
16 | [32m.[0m[31mF[0m
17 |
18 | 2) Another group with a failure has an example that fails
19 | [31mFailure/Error: [0m[32mexpect[0m([1;34m1[0m).to eq [1;34m2[0m[0m
20 | [31m[0m
21 | [31m expected: 2[0m
22 | [31m got: 1[0m
23 | [31m[0m
24 | [31m (compared using ==)[0m
25 | [36m# ./a_spec.rb:13:in `block (2 levels) in '[0m
26 |
27 | [32m.[0m
28 |
29 | Finished in 0.0307 seconds (files took 0.08058 seconds to load)
30 | [31m4 examples, 2 failures[0m
31 |
32 | Failed examples:
33 |
34 | [31mrspec ./a_spec.rb:2[0m [36m# A group with a failure has an example that fails[0m
35 | [31mrspec ./a_spec.rb:12[0m [36m# Another group with a failure has an example that fails[0m
36 |
37 |
--------------------------------------------------------------------------------