diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..5309762cb2 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,22 @@ +# Your name + +Please write your full name here to make it easier to find your pull request. + +# User stories + +Please list which user stories you've implemented (delete the ones that don't apply). + +- [ ] User story 1: "I would like to see a list of dishes with prices" +- [ ] User story 2: "I would like to be able to select some number of several available dishes" +- [ ] User story 3: "I would like to check that the total I have been given matches the sum of the various dishes in my order" +- [ ] User story 4: "I would like to receive a text such as "Thank you! Your order was placed and will be delivered before 18:52" after I have ordered" + +# README checklist + +Does your README contains instructions for + +- [ ] how to install, +- [ ] how to run, +- [ ] and how to test your code? + +[Here is a pill](https://github.com/makersacademy/course/blob/main/pills/readmes.md) that can help you write a great README! \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5700a5c81d..d1a1edf06f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /**/.DS_Store /coverage + +# Local cache of Rubocop remote config +.rubocop-* diff --git a/.rubocop.yml b/.rubocop.yml index afc04377ea..f1b05987d0 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -7,483 +7,7 @@ # The linter file that doesn't lead junior developers to bad habits. # https://github.com/makersacademy/scaffolint # -# Problems (eg obselete names) may be due to an incompatible version. -# Check your Rubocop version with `rubocop -v` in the command line. -# -# Tested with Rubocop version 0.71.0 -# -# Introduction -# ============ -# -# Our order of priorities: -# -# 1. Conforming your code to the styleguide. -# 2. The styleguide being thorough and complete. -# -# This file relaxes Rubocop a bit so you can learn about code quality rather -# than just following the rules. Some guidelines can result in worse code if you -# don't know why they are there. For instance, if a line is too long, you might -# be tempted to simply abbreviate your variable names - making your code harder -# to read. -# -# We prioritize rules that offer good, easily incorporated feedback on improving -# your code, without being overwhelming or requiring experienced judgement. -# -# As you become a better developer you will remove or amend this file according -# to what you think good code should look like. -# -# Physical Code Size -# ================== -# -# Sometimes beginner devs interpret line or block length restrictions as a -# reason to make things so abbreviated as to be unreadable. These messages are -# designed to make you write more readable code - not less. -# -# We want to encourage testing, but it can be verbose in the early stages. -# So we'll give you a break. As you learn, try removing the next two sections. - -Metrics/LineLength: - Exclude: - - 'spec/**/*' - - 'test/**/*' - Max: 100 - -Metrics/BlockLength: - Exclude: - - 'spec/**/*' - - 'test/**/*' - -# Code Style -# ========== -# -# Many devs, upon running a linter for the first time, see a big wall of errors -# of dubious necessity and put it in the 'way too much trouble' box. Beginners -# usually have far more pressing concerns than which sort of quotes they use. -# -# This makes Rubocop have a bigger 'payoff' for beginners without so much of -# the punishment. We focus our linting on things that significantly impact -# readability, expressiveness, or teach a dev new things. For example: -# -# * Indentation & whitespace (inconsistency, really gross stuff like `a=1`) -# * Easy wins in expressiveness (e.g. guard clauses — nice opportunity to -# inject concretes) -# * Egregious non-idiomatic ruby like `def getFilename` - -IndentationConsistency: - Enabled: true -IndentationWidth: - Enabled: true -AccessorMethodName: - Enabled: true -BlockEndNewline: - Enabled: true -DefWithParentheses: - Enabled: true -EmptyLineBetweenDefs: - Enabled: true -EmptyLines: - Enabled: true -ExtraSpacing: - Enabled: true -GuardClause: - Enabled: true -IdenticalConditionalBranches: - Enabled: true -InverseMethods: - Enabled: true -LeadingCommentSpace: - Enabled: true -NegatedIf: - Enabled: true -NegatedWhile: - Enabled: true -NilComparison: - Enabled: true -Not: - Enabled: true -NumericLiterals: - Enabled: true -NumericPredicate: - Enabled: true -OneLineConditional: - Enabled: true -RedundantParentheses: - Enabled: true -RedundantSelf: - Enabled: true -Style/SafeNavigation: - Enabled: true -SelfAssignment: - Enabled: true -SpaceAfterColon: - Enabled: true -SpaceAfterComma: - Enabled: true -SpaceAfterMethodName: - Enabled: true -SpaceAfterNot: - Enabled: true -SpaceAfterSemicolon: - Enabled: true -SpaceAroundBlockParameters: - Enabled: true -SpaceAroundEqualsInParameterDefault: - Enabled: true -SpaceAroundKeyword: - Enabled: true -SpaceAroundOperators: - Enabled: true -SpaceBeforeBlockBraces: - Enabled: true -SpaceBeforeComma: - Enabled: true -SpaceBeforeComment: - Enabled: true -SpaceBeforeFirstArg: - Enabled: true -SpaceBeforeSemicolon: - Enabled: true -SpaceInLambdaLiteral: - Enabled: true -SpaceInsideArrayPercentLiteral: - Enabled: true -SpaceInsideBlockBraces: - Enabled: true -SpaceInsideReferenceBrackets: - Enabled: true -SpaceInsideArrayLiteralBrackets: - Enabled: true -SpaceInsideHashLiteralBraces: - Enabled: true -SpaceInsideParens: - Enabled: true -SpaceInsidePercentLiteralDelimiters: - Enabled: true -SpaceInsideRangeLiteral: - Enabled: true -SpaceInsideStringInterpolation: - Enabled: true -SymbolLiteral: - Enabled: true -TrailingBlankLines: - Enabled: true -TrivialAccessors: - Enabled: true +# Configure Rubocop to use the config file in the Scaffolint GitHub repo -# Rubocop doesn't make disabling all cops in a given group easy, so we list... -AccessModifierIndentation: - Enabled: false -Alias: - Enabled: false -AlignArray: - Enabled: false -AlignHash: - Enabled: false -AlignParameters: - Enabled: false -AndOr: - Enabled: false -ArrayJoin: - Enabled: false -AsciiComments: - Enabled: false -AsciiIdentifiers: - Enabled: false -Attr: - Enabled: false -AutoResourceCleanup: - Enabled: false -BarePercentLiterals: - Enabled: false -BeginBlock: - Enabled: false -BlockComments: - Enabled: false -BlockDelimiters: - Enabled: false -BracesAroundHashParameters: - Enabled: false -CaseEquality: - Enabled: false -CaseIndentation: - Enabled: false -CharacterLiteral: - Enabled: false -ClassAndModuleChildren: - Enabled: false -ClassCheck: - Enabled: false -ClassMethods: - Enabled: false -ClassVars: - Enabled: false -ClosingParenthesisIndentation: - Enabled: false -CollectionMethods: - Enabled: false -ColonMethodCall: - Enabled: false -CommandLiteral: - Enabled: false -CommentAnnotation: - Enabled: false -CommentIndentation: - Enabled: false -ConditionalAssignment: - Enabled: false -Copyright: - Enabled: false -Documentation: - Enabled: false -DocumentationMethod: - Enabled: false -DotPosition: - Enabled: false -DoubleNegation: - Enabled: false -EachForSimpleLoop: - Enabled: false -EachWithObject: - Enabled: false -ElseAlignment: - Enabled: false -EmptyCaseCondition: - Enabled: false -EmptyElse: - Enabled: false -EmptyLineAfterMagicComment: - Enabled: false -EmptyLinesAroundAccessModifier: - Enabled: false -EmptyLinesAroundBeginBody: - Enabled: false -EmptyLinesAroundBlockBody: - Enabled: false -EmptyLinesAroundClassBody: - Enabled: false -EmptyLinesAroundExceptionHandlingKeywords: - Enabled: false -EmptyLinesAroundMethodBody: - Enabled: false -EmptyLinesAroundModuleBody: - Enabled: false -EmptyLiteral: - Enabled: false -EmptyMethod: - Enabled: false -Encoding: - Enabled: false -EndBlock: - Enabled: false -EndOfLine: - Enabled: false -EvenOdd: - Enabled: false -FirstArrayElementLineBreak: - Enabled: false -FirstHashElementLineBreak: - Enabled: false -FirstMethodArgumentLineBreak: - Enabled: false -FirstMethodParameterLineBreak: - Enabled: false -Layout/IndentFirstArgument: - Enabled: false -FlipFlop: - Enabled: false -For: - Enabled: false -FormatString: - Enabled: false -FrozenStringLiteralComment: - Enabled: false -GlobalVars: - Enabled: false -HashSyntax: - Enabled: false -IfInsideElse: - Enabled: false -IfUnlessModifier: - Enabled: false -IfUnlessModifierOfIfUnless: - Enabled: false -IfWithSemicolon: - Enabled: false -ImplicitRuntimeError: - Enabled: false -IndentFirstArrayElement: - Enabled: false -IndentAssignment: - Enabled: false -IndentFirstHashElement: - Enabled: false -IndentHeredoc: - Enabled: false -InfiniteLoop: - Enabled: false -InitialIndentation: - Enabled: false -InlineComment: - Enabled: false -Lambda: - Enabled: false -LambdaCall: - Enabled: false -LineEndConcatenation: - Enabled: false -MethodCallWithArgsParentheses: - Enabled: false -MethodCallWithoutArgsParentheses: - Enabled: false -MethodCalledOnDoEndBlock: - Enabled: false -MethodDefParentheses: - Enabled: false -MethodMissingSuper: - Enabled: false -MissingRespondToMissing: - Enabled: false -MissingElse: - Enabled: false -MixinGrouping: - Enabled: false -ModuleFunction: - Enabled: false -MultilineArrayBraceLayout: - Enabled: false -MultilineAssignmentLayout: - Enabled: false -MultilineBlockChain: - Enabled: false -MultilineBlockLayout: - Enabled: false -MultilineHashBraceLayout: - Enabled: false -MultilineIfModifier: - Enabled: false -MultilineIfThen: - Enabled: false -MultilineMemoization: - Enabled: false -MultilineMethodCallBraceLayout: - Enabled: false -MultilineMethodCallIndentation: - Enabled: false -MultilineMethodDefinitionBraceLayout: - Enabled: false -MultilineOperationIndentation: - Enabled: false -MultilineTernaryOperator: - Enabled: false -MutableConstant: - Enabled: false -NestedModifier: - Enabled: false -NestedParenthesizedCalls: - Enabled: false -NestedTernaryOperator: - Enabled: false -Next: - Enabled: false -NonNilCheck: - Enabled: false -NumericLiteralPrefix: - Enabled: false -BinaryOperatorParameterName: - Enabled: false -OptionHash: - Enabled: false -OptionalArguments: - Enabled: false -ParallelAssignment: - Enabled: false -ParenthesesAroundCondition: - Enabled: false -PercentLiteralDelimiters: - Enabled: false -PercentQLiterals: - Enabled: false -PerlBackrefs: - Enabled: false -PreferredHashMethods: - Enabled: false -Proc: - Enabled: false -RaiseArgs: - Enabled: false -RedundantBegin: - Enabled: false -RedundantException: - Enabled: false -RedundantFreeze: - Enabled: false -RedundantReturn: - Enabled: false -RegexpLiteral: - Enabled: false -RescueEnsureAlignment: - Enabled: false -RescueModifier: - Enabled: false -Semicolon: - Enabled: false -Send: - Enabled: false -SignalException: - Enabled: false -SingleLineBlockParams: - Enabled: false -SingleLineMethods: - Enabled: false -SpecialGlobalVars: - Enabled: false -StabbyLambdaParentheses: - Enabled: false -StringLiterals: - Enabled: false -StringLiteralsInInterpolation: - Enabled: false -StringMethods: - Enabled: false -StructInheritance: - Enabled: false -SymbolArray: - Enabled: false -SymbolProc: - Enabled: false -Tab: - Enabled: false -TernaryParentheses: - Enabled: false -TrailingCommaInArguments: - Enabled: false -TrailingCommaInArrayLiteral: - Enabled: false -TrailingCommaInHashLiteral: - Enabled: false -TrailingUnderscoreVariable: - Enabled: false -TrailingWhitespace: - Enabled: false -UnlessElse: - Enabled: false -UnneededCapitalW: - Enabled: false -UnneededInterpolation: - Enabled: false -UnneededPercentQ: - Enabled: false -VariableInterpolation: - Enabled: false -VariableNumber: - Enabled: false -WhenThen: - Enabled: false -WhileUntilDo: - Enabled: false -WhileUntilModifier: - Enabled: false -WordArray: - Enabled: false -ZeroLengthPredicate: - Enabled: false +inherit_from: + - https://raw.githubusercontent.com/makersacademy/scaffolint/v2.2.0/.rubocop.yml diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index 57cf282ebb..0000000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.6.5 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5e95214805..9adc651647 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,4 +18,4 @@ Guidelines ------- * Ensure you've understood the specification and built the code according to the challenge guidelines. -* Read through [Code Reviews :pill:](https://github.com/makersacademy/course/blob/master/pills/code_reviews.md) to understand what we're looking for in your code. +* Read through [Code Reviews :pill:](https://github.com/makersacademy/course/blob/main/pills/code_reviews.md) to understand what we're looking for in your code. diff --git a/Gemfile b/Gemfile index 006a1bffbc..35de4a7f0e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1,13 @@ source 'https://rubygems.org' -gem 'capybara' -gem 'rake' -gem 'rspec' -gem 'rubocop', '0.71.0' -gem 'simplecov', require: false, group: :test -gem 'simplecov-console', require: false, group: :test +ruby '3.0.2' + +group :test do + gem 'rspec' + gem 'simplecov', require: false, group: :test + gem 'simplecov-console', require: false, group: :test +end + +group :development, :test do + gem 'rubocop', '1.20' +end diff --git a/Gemfile.lock b/Gemfile.lock index d8d88d2c61..66064703c7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,82 +1,66 @@ GEM remote: https://rubygems.org/ specs: - addressable (2.7.0) - public_suffix (>= 2.0.2, < 5.0) ansi (1.5.0) - ast (2.4.0) - capybara (3.29.0) - addressable - mini_mime (>= 0.1.3) - nokogiri (~> 1.8) - rack (>= 1.6.0) - rack-test (>= 0.6.3) - regexp_parser (~> 1.5) - xpath (~> 3.2) - diff-lcs (1.3) - docile (1.3.2) - jaro_winkler (1.5.4) - json (2.2.0) - mini_mime (1.0.2) - mini_portile2 (2.4.0) - nokogiri (1.10.5) - mini_portile2 (~> 2.4.0) - parallel (1.18.0) - parser (2.6.5.0) - ast (~> 2.4.0) - public_suffix (4.0.1) - rack (2.0.7) - rack-test (1.1.0) - rack (>= 1.0, < 3) + ast (2.4.2) + diff-lcs (1.4.4) + docile (1.4.0) + parallel (1.20.1) + parser (3.0.2.0) + ast (~> 2.4.1) rainbow (3.0.0) - rake (13.0.1) - regexp_parser (1.6.0) - rspec (3.9.0) - rspec-core (~> 3.9.0) - rspec-expectations (~> 3.9.0) - rspec-mocks (~> 3.9.0) - rspec-core (3.9.0) - rspec-support (~> 3.9.0) - rspec-expectations (3.9.0) + regexp_parser (2.1.1) + rexml (3.2.5) + rspec (3.10.0) + rspec-core (~> 3.10.0) + rspec-expectations (~> 3.10.0) + rspec-mocks (~> 3.10.0) + rspec-core (3.10.1) + rspec-support (~> 3.10.0) + rspec-expectations (3.10.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.9.0) - rspec-mocks (3.9.0) + rspec-support (~> 3.10.0) + rspec-mocks (3.10.2) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.9.0) - rspec-support (3.9.0) - rubocop (0.71.0) - jaro_winkler (~> 1.5.1) + rspec-support (~> 3.10.0) + rspec-support (3.10.2) + rubocop (1.20.0) parallel (~> 1.10) - parser (>= 2.6) + parser (>= 3.0.0.0) rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml + rubocop-ast (>= 1.9.1, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 1.7) - ruby-progressbar (1.10.1) - simplecov (0.17.1) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.11.0) + parser (>= 3.0.1.1) + ruby-progressbar (1.11.0) + simplecov (0.21.2) docile (~> 1.1) - json (>= 1.8, < 3) - simplecov-html (~> 0.10.0) - simplecov-console (0.6.0) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-console (0.9.1) ansi simplecov terminal-table - simplecov-html (0.10.2) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - unicode-display_width (1.6.0) - xpath (3.2.0) - nokogiri (~> 1.8) + simplecov-html (0.12.3) + simplecov_json_formatter (0.1.3) + terminal-table (3.0.1) + unicode-display_width (>= 1.1.1, < 3) + unicode-display_width (2.0.0) PLATFORMS ruby DEPENDENCIES - capybara - rake rspec - rubocop (= 0.71.0) + rubocop (= 1.20) simplecov simplecov-console +RUBY VERSION + ruby 3.0.2p107 + BUNDLED WITH - 1.17.3 + 2.2.26 diff --git a/README.md b/README.md index 49efd78329..dbcb154e43 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,6 @@ Takeaway Challenge Instructions ------- -* Challenge time: rest of the day and weekend, until Monday 9am * Feel free to use google, your notes, books, etc. but work on your own * If you refer to the solution of another coach or student, please put a link to that in your README * If you have a partial solution, **still check in a partial solution** @@ -50,7 +49,7 @@ I would like to receive a text such as "Thank you! Your order was placed and wil * Hints on functionality to implement: * Ensure you have a list of dishes with prices - * Place the order by giving the list of dishes, their quantities and a number that should be the exact total. If the sum is not correct the method should raise an error, otherwise the customer is sent a text saying that the order was placed successfully and that it will be delivered 1 hour from now, e.g. "Thank you! Your order was placed and will be delivered before 18:52". + * The text should state that the order was placed successfully and that it will be delivered 1 hour from now, e.g. "Thank you! Your order was placed and will be delivered before 18:52". * The text sending functionality should be implemented using Twilio API. You'll need to register for it. It’s free. * Use the twilio-ruby gem to access the API * Use the Gemfile to manage your gems @@ -63,7 +62,9 @@ I would like to receive a text such as "Thank you! Your order was placed and wil * A free account on Twilio will only allow you to send texts to "verified" numbers. Use your mobile phone number, don't worry about the customer's mobile phone. -* **WARNING** think twice before you push your mobile number or any private details to a public space like Github. Now is a great time to think about security and how you can keep your private information secret. You might want to explore environment variables. +> :warning: **WARNING:** think twice before you push your **mobile number** or **Twilio API Key** to a public space like GitHub :eyes: +> +> :key: Now is a great time to think about security and how you can keep your private information secret. You might want to explore environment variables. * Finally submit a pull request before Monday at 9am with your solution or partial solution. However much or little amount of code you wrote please please please submit a pull request before Monday at 9am @@ -71,12 +72,12 @@ I would like to receive a text such as "Thank you! Your order was placed and wil In code review we'll be hoping to see: * All tests passing -* High [Test coverage](https://github.com/makersacademy/course/blob/master/pills/test_coverage.md) (>95% is good) +* High [Test coverage](https://github.com/makersacademy/course/blob/main/pills/test_coverage.md) (>95% is good) * The code is elegant: every class has a clear responsibility, methods are short etc. -Reviewers will potentially be using this [code review rubric](docs/review.md). Referring to this rubric in advance will make the challenge somewhat easier. You should be the judge of how much challenge you want this weekend. +Reviewers will potentially be using this [code review rubric](docs/review.md). Referring to this rubric in advance will make the challenge somewhat easier. You should be the judge of how much challenge you want this at this moment. Notes on Test Coverage ------------------ -You can see your [test coverage](https://github.com/makersacademy/course/blob/master/pills/test_coverage.md) when you run your tests. +You can see your [test coverage](https://github.com/makersacademy/course/blob/main/pills/test_coverage.md) when you run your tests. diff --git a/Rakefile b/Rakefile deleted file mode 100644 index f2d77e4840..0000000000 --- a/Rakefile +++ /dev/null @@ -1,5 +0,0 @@ -require 'rspec/core/rake_task' - -RSpec::Core::RakeTask.new :spec - -task default: [:spec] diff --git a/check.sh b/check.sh new file mode 100755 index 0000000000..1469749226 --- /dev/null +++ b/check.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +# This script is used by Makers to ensure that the challenges stay up to date. +# If you're a student, you don't need to run it. But you can if you like! + +set -Eeuo pipefail +trap cleanup SIGINT SIGTERM ERR + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P) + +setup_colors() { + if [[ -t 2 ]] && [[ -z "${NO_COLOR-}" ]] && [[ "${TERM-}" != "dumb" ]]; then + NOFORMAT='\033[0m' RED='\033[0;31m' GREEN='\033[0;32m' ORANGE='\033[0;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' YELLOW='\033[1;33m' + else + NOFORMAT='' RED='' GREEN='' ORANGE='' BLUE='' PURPLE='' CYAN='' YELLOW='' + fi +} + +cleanup() { + trap - SIGINT SIGTERM ERR + die "${RED}Checks failed${NOFORMAT}" +} + +msg() { + echo >&2 -e "${1-}" +} + +die() { + local msg=$1 + local code=${2-1} # default exit status 1 + msg "$msg" + exit "$code" +} + +setup_colors + +msg "${BLUE}Integrity check using Ruby version ${ORANGE}$(ruby -v)${NOFORMAT}" +msg "${BLUE} • Installing bundler${NOFORMAT}" +gem install bundler +msg "${BLUE} • Running bundle install${NOFORMAT}" +bundle install +msg "${BLUE} • Running rspec${NOFORMAT}" +bundle exec rspec +msg "${BLUE} • Running rubocop${NOFORMAT}" +bundle exec rubocop +exit 0 diff --git a/docs/review.md b/docs/review.md index 6d05ecb804..b43def6b17 100644 --- a/docs/review.md +++ b/docs/review.md @@ -3,8 +3,6 @@ Welcome to the code review for Takeaway Challenge! Again, don't worry - you are If you don't feel comfortable giving technical feedback at this stage, try going through this guide with your reviewee and review the code together. -Please use [this form](https://goo.gl/forms/kl8BCIwaEqu9G0Nx2) to tick off where your reviewee has successfully avoided these issues! This form helps us get an overall picture of how the whole cohort is doing - it's not an assessment of an individual student. - # Step 0: Checkout and Run tests Please checkout your reviewee's code and run their tests. Read the code and try some manual feature tests in IRB. How easy is it to understand the structure of their code? How readable is their code? Did you need to make any cognitive leaps to 'get it'? @@ -17,7 +15,7 @@ Please do include all the gems you use in your Gemfile. This is an important cou ## README updated -Every good code base will have its README updated following the [contribution notes](https://github.com/makersacademy/takeaway-challenge/blob/master/CONTRIBUTING.md), i.e. +Every good code base will have its README updated following the [contribution notes](https://github.com/makersacademy/takeaway-challenge/blob/main/CONTRIBUTING.md), i.e. * Make sure you have written your own README that briefly explains your approach to solving the challenge. * If your code isn't finished it's not ideal but acceptable as long as you explain in your README where you got to and how you would plan to finish the challenge. @@ -54,7 +52,7 @@ The README is a great place to show the full story of how your app is used (from ## Tests should test real behaviours not stubs -We already talked about ["Vacuous" tests](https://github.com/makersacademy/airport_challenge/blob/master/docs/review.md#vacuous-tests) in the airport challenge code review. The example there focused on how we shouldn't test the behaviour of a double; but we can get into similar trouble if we are stubbing a real object, e.g. +You may have read about ["Vacuous" tests](https://github.com/makersacademy/airport_challenge/blob/main/docs/review.md#avoid-vacuous-tests) in the airport challenge code review. The example there focused on how we shouldn't test the behaviour of a double; but we can get into similar trouble if we are stubbing a real object, e.g. ```ruby it 'sends a payment confirmation text message' do @@ -65,9 +63,9 @@ end In the above the `expect(subject).to receive(:send_sms)` command "stubs" out any existing method called `send_sms` on the subject. Using `expect` instead of `allow` means that at the end of the it block, RSpec checks that subject did receive the message `send_sms`, which we have ensured by calling `subject.send_sms`, so this test passes without ever touching the application code. -You can confirm this test is 'vacuous' by checking that the [test coverage](https://github.com/makersacademy/course/blob/master/pills/test_coverage.md) doesn't change when you remove it. +You can confirm this test is 'vacuous' by checking that the [test coverage](https://github.com/makersacademy/course/blob/main/pills/test_coverage.md) doesn't change when you remove it. -In general you shouldn't be stubbing out behaviour on the object under test. The two key exceptions are when you have randomness or a 3rd party API. We saw how to [stub random behaviour](https://github.com/makersacademy/airport_challenge/blob/master/docs/review.md#handling-randomness-in-tests) in the airport challenge code review, but how do we stub a 3rd party API? See the next section. +In general you shouldn't be stubbing out behaviour on the object under test. The two key exceptions are when you have randomness or a 3rd party API. We saw how to [stub random behaviour](https://github.com/makersacademy/airport_challenge/blob/main/docs/review.md#handling-randomness-in-tests) in the airport challenge code review, but how do we stub a 3rd party API? See the next section. ## Stubbing the Twilio API @@ -78,7 +76,7 @@ The simplest approach is to stub out a method that calls the service, for exampl ```ruby class Takeaway - def complete_order + def complete_order(price) send_text("Thank you for your order: £#{total_price}") end @@ -107,11 +105,11 @@ describe Takeaway end ``` -This ensures that Takeaway#complete_order gets some test coverage and that no SMS will be sent by our tests. This is acceptable, but we still don't have very good test coverage. See the pill on [levels of stubbing 3rd party services](https://github.com/makersacademy/course/blob/master/pills/levels_of_stubbing.md) for some alternatives. +This ensures that Takeaway#complete_order gets some test coverage and that no SMS will be sent by our tests. This is acceptable, but we still don't have very good test coverage. See the pill on [levels of stubbing 3rd party services](https://github.com/makersacademy/course/blob/main/pills/levels_of_stubbing.md) for some alternatives. ## Unit vs Integration tests -Note that if you create real objects (not doubles) in your unit tests other than that which is the subject, then you are using the [Chicago style)[http://programmers.stackexchange.com/questions/123627/what-are-the-london-and-chicago-schools-of-tdd] of unit testing (also called [integration testing](http://stackoverflow.com/a/7876055/316729)). In general you want to separate up your unit from your integration (or "feature") tests. Unit tests can just rest in the root of the spec folder, but features of integration tests should go in a subfolder (spec/features or spec/integration) or even in a separate folder on the root directory to allow them to run completely separately. +Note that if you create real objects (not doubles) in your unit tests other than that which is the subject, then you are using the [Chicago style](http://programmers.stackexchange.com/questions/123627/what-are-the-london-and-chicago-schools-of-tdd) of unit testing (also called [integration testing](http://stackoverflow.com/a/7876055/316729)). In general you want to separate up your unit from your integration (or "feature") tests. Unit tests can just rest in the root of the spec folder, but features of integration tests should go in a subfolder (spec/features or spec/integration) or even in a separate folder on the root directory to allow them to run completely separately. At Makers Academy we recommend using the London style with doubles to effectively isolate the single class being tested in a unit test. @@ -186,7 +184,7 @@ end ## Use of modules -There are two main uses of modules in Ruby; one is to provide 'utility' libraries (which are sometimes a code smell) and the other is to provide mixins. However, using a module as a mixin can violate the Single Responsibility Principle. Although code is _defined_ in the module, when it is `include`d in a class, its behaviour becomes part of that class and therefore part of the class's responsibilities. Shared behavioiur can be refactored into mixins (e.g. `BikeContainer` in Boris Bikes), but other responsibilities the class is dependent on (e.g. sending text messages for the restaurant) should be injected (see [Appropriate use of Dependency Injection](appropriate-use-of-dependency-injection)). +There are two main uses of modules in Ruby; one is to provide 'utility' libraries (which are sometimes a code smell) and the other is to provide mixins. However, using a module as a mixin can violate the Single Responsibility Principle. Although code is _defined_ in the module, when it is `include`d in a class, its behaviour becomes part of that class and therefore part of the class's responsibilities. Shared behaviour can be refactored into mixins (e.g. `BikeContainer` in Boris Bikes), but other responsibilities the class is dependent on (e.g. sending text messages for the restaurant) should be injected (see [this practical on dependency injection](https://github.com/makersacademy/skills-workshops/blob/f5b4801840fe07d26ff70341652dc81dcda12289/practicals/object_oriented_design/dependency_injection.md)). ## Law of Demeter diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ff9361ad27..252747d899 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,3 @@ -require 'capybara/rspec' require 'simplecov' require 'simplecov-console'