Red-Green-Refactor by Example

Learn the red-green-refactor loop, the primary principle of TDD. Write tests first, watch them fail, write code incrementally until the tests pass. With passing tests, use the opportunity to refactor.
This is a companion discussion topic for the original entry at https://thoughtbot.com/upcase/videos/red-green-refactor-by-example

you have initialize misspelled in your exercise code.

Thanks for reporting! We updated it this morning, apologies for the typo.

I see now that the exercise system (feedback system) is not used here. So itā€™s safe to assume we post a repo link on the forum to get our code reviewed?

Hey @iamarmanjon, sorry for the confusion here. The exercise included in this videoā€™s notes is intended to provide a structure for you to try out TDD easily, but it is not an exercise in the traditional sense where the solution is the focus.

Instead, the focus is on the process. We wanted to provide a first TDD problem for you to get comfortable with the TDD workflow, taking small steps, working on each failure one at a time, etc. That said, the end result (the final spec suite and implementation) are not expected to be very interesting or different between users. Again, the process is the focus here, not the solution.

As such, we chose to provide this as part of the notes, rather than using the exercise system. That said, step 4 in the trail is a full blown exercise using our Git system where youā€™re asked to refactor a spec file. In that case the solution is interesting, and thus we use the exercise system.

Sorry for the confusion here, but hopefully the above clears things up. Let us know if you have any more questions.

2 Likes

thanks @christoomey that clears up a lot.

1 Like

require ā€œrspec/autorunā€

describe Calculator do
describe ā€œ#addā€ do
it ā€œreturns the sum of its two argumentsā€ do
calc = Calculator.new

  expect(calc.add(5, 10)).to eq(15)
end

end
end

Unable to run the first test (3min 52) due to the following error

uby calculator_ruby_tdd.rb
/Users/neilpatel/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in require': cannot load such file -- rspec/autorun (LoadError) from /Users/neilpatel/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in requireā€™

@neilp666 it sounds like you might not have the rspec gem installed. You can run the following at the command line to confirm:

gem search rspec --local

1 Like

Sometimes I just need a simple example like this to get me back into focusing more on the process of TDD. More often than not I drift away from a strict TDD process to a process that sometimes has tests written after the fact.

This is my solution for the exercise

Any opinion?

Here is my attempt. Iā€™m still learning Ruby.

My solution:

Iā€™m having wrong number of arguments (given 3, expected 0) issue on line 17, which is the initialize method. The initialiser itself, along with whole spec, was copied and pasted from the show notes:

def initialize(first_name:, middle_name: nil, last_name:)
  @first_name = first_name
  @middle_name = middle_name
  @last_name = last_name
end

And actual failure happens when I am creating new Person like so:

person = Person.new("Askhat", "Maratovich", "Bikmetov")

Iā€™m pretty sure the elephant is in the room, but could anyone point me on it?

ruby -v 2.3.1
rspec -v 3.5.3

I believe the issue here is your initialize expects keyword arguments, while your usage is passing positional arguments. So instead of the Person.new as you have it, youā€™ll want to do:

# note: only breaking across lines for readability
person = Person.new(
  first_name: "Askhat",
  middle_name: "Maratovich",
  last_name: "Bikmetov"
)

Note: We have a Weekly Iteration on Ruby Keyword Arguments if you want to brush up.

You wonā€™t believe how stupid Iā€™m feeling right now, named arguments, obviously. Much obliged!
BTW ruby could be little more articulate on this, instead of wrong number, donā€™t you think?

Iā€™m always in favor of better error messages :slight_smile:

1 Like

Hereā€™s my attempt to solving this: Red-Green-Refactor by Example related exercise as part of the Fundamentals of TDD course in Upcase (https://thoughtbot.com/upcase/videos/red-green-refactor-by-example) Ā· GitHub . Happy to receive any feedback to improve this further.

Thank you.

Thats what I came up with: coding-challenges/tdd-one.rb at main Ā· Witta11/coding-challenges Ā· GitHub

i was gettting failed tests when the the strings are being concatenated it took me longer than i care to admit to figure out uses whitespace i used the following function to strip the white space out

def squish(s)
    s.strip.gsub(/\s+/, " ")  # this replaces the white space with an actual space
end

great video. hereā€™s my solution

class Person
  def initialize(first_name:, middle_name: nil, last_name:)
    @first_name = first_name
    @middle_name = middle_name
    @last_name = last_name
  end

  def full_name
    [@first_name, @middle_name, @last_name].reject(&:nil?).join(" ")
  end

  def full_name_with_middle_initial
    return [@first_name, @last_name].join(" ") if @middle_name.nil?

    [@first_name, @middle_name[0] + ".", @last_name].reject(&:nil?).join(" ")
  end

  def initials
    return [@first_name[0], @last_name[0]].join(".") if @middle_name.nil?

    [@first_name[0], @middle_name[0], @last_name[0]].reject(&:nil?).join(".")
  end
end

RSpec.describe Person do
  describe "#full_name" do
    it "concatenates first name, middle name, and last name with spaces" do
      person = Person.new(
        first_name: "Tuan",
        middle_name: "Viet",
        last_name: "Nguyen"
      )
      expect(person.full_name).to eq "Tuan Viet Nguyen"
    end

    it "does not add extra spaces if middle name is missing" do
      person = Person.new(
        first_name: "Tuan",
        last_name: "Nguyen"
      )
      expect(person.full_name).to eq "Tuan Nguyen"
    end
  end

  describe "#full_name_with_middle_initial" do
    context "middle name is missing" do
      it "concatenates first name and last name with spaces" do
        person = Person.new(
          first_name: "Tuan",
          last_name: "Nguyen"
        )
        expect(person.full_name_with_middle_initial).to eq "Tuan Nguyen"
      end
    end

    context "middle name is not missing" do
      it "concatenates first name, middle name initial, and last name with spaces" do
        person = Person.new(
          first_name: "Tuan",
          middle_name: "Viet",
          last_name: "Nguyen"
        )
        expect(person.full_name_with_middle_initial).to eq "Tuan V. Nguyen"
      end
    end
  end

  describe "#initials" do
    context "middle name is missing" do
      it "concatenates first name initial and last name initial" do
        person = Person.new(
          first_name: "Tuan",
          last_name: "Nguyen"
        )
        expect(person.initials).to eq "T.N"
      end
    end

    context "middle name is not missing" do
      it "concatenates first name initial, middle name initial, and last name initial" do
        person = Person.new(
          first_name: "Tuan",
          middle_name: "Viet",
          last_name: "Nguyen"
        )
        expect(person.initials).to eq "T.V.N"
      end
    end
  end
end