2. Test-First Ruby: Hello

Now that you have some experience with write Ruby code, let's get familiar with the concept of testing.

Making Our First Test Pass

As a Ruby developer, being able to write tests and developing your code in a Test Driven manner will take you far in your career. That's why we incorporate Test Driven Development practices from the start. Don't be freaked out by these terms, slowly, you will get used to these terms.

Test Driven Development

Let's say we want to write a method called say_hello that takes in a name and outputs "Hello, name!".

When we start building the method, we first intuitively think about what the output should be.

For example in this case, if I input "Mark", then the output should be "Hello, Mark!". If the input is "Bob", then the output should be "Hello, Bob!".

Notice how we are thinking about what the output should be before we have started writing any code.

After we think about what the output should be, the next step is to actually write the code and see if it works.

If it doesn't work, we edit the code, run the code, and repeat, until it finally works.

This is the basic methodology of TDD:

  1. Before writing any code, we think about what the output should be
  2. We write the code
  3. We test to see if the output matches what we expected
  4. If it didn't match, rewrite the code until the output matches

By doing this, not only can we be more confident about our code, but we can also write higher quality code as well.

You will learn more in-depth about Test Driven Development in the later lessons - for now, just know that knowing this process is extremely important as a developer.

Getting Started

First, let's download zip file from https://github.com/namespace-team/ruby_fundamentals_challenges/archive/master.zip

Once you have unarchived the zip file into your workspace, let's navigate to the hello directory. In the workspace terminal, type in the following command and press enter:

cd hello

Next, type in the following command and press enter:

bundle install

This command installs a bunch of packages and dependencies.

Next, let's run the following command:

rspec

This will run some tests to see if the code is working or not. Since you haven't written any code yet, you should see the failing tests.

FFF

Failures:

  1) #hello the hello function says hello
     Failure/Error: expect(hello).to eq("Hello!")

     NameError:
       undefined local variable or method `hello' for #<RSpec::ExampleGroups::Hello::TheHelloFunction:0x000055f71e15b740>
     # ./spec/hello_spec.rb:7:in `block (3 levels) in <top (required)>'

  2) #hello the greet function says hello to someone
     Failure/Error: expect(greet("Alice")).to eq("Hello, Alice!")

     NoMethodError:
       undefined method `greet' for #<RSpec::ExampleGroups::Hello::TheGreetFunction:0x000055f71e159148>
     # ./spec/hello_spec.rb:13:in `block (3 levels) in <top (required)>'

  3) #hello the greet function says hello to someone else
     Failure/Error: expect(greet("Bob")).to eq("Hello, Bob!")

     NoMethodError:
       undefined method `greet' for #<RSpec::ExampleGroups::Hello::TheGreetFunction:0x000055f71e15bb78>
     # ./spec/hello_spec.rb:17:in `block (3 levels) in <top (required)>'

Finished in 0.00452 seconds (files took 0.19466 seconds to load)
3 examples, 3 failures

Failed examples:

rspec ./spec/hello_spec.rb:6 # #hello the hello function says hello
rspec ./spec/hello_spec.rb:12 # #hello the greet function says hello to someone
rspec ./spec/hello_spec.rb:16 # #hello the greet function says hello to someone else

The first failure you'll see is the NameError:

1) #hello the hello function says hello
Failure/Error: expect(hello).to eq("Hello!")

NameError:
undefined local variable or method `hello' for #<RSpec::ExampleGroups::StringCompressor::TheHelloFunction:0x00562eeffa3718>
# ./spec/hello_spec.rb:7:in `block (3 levels) in <top (required)>'

The first error is saying that the method is not defined. Let's define that method in our hello.rb file inside the lib directory.

def hello

end

Save the file and run rspec.

1) #hello the hello function says hello
    Failure/Error: expect(hello).to eq("Hello!")

      expected: "Hello!"
          got: nil

      (compared using ==)
    # ./spec/hello_spec.rb:7:in `block (3 levels) in <top (required)>'

You should now see a different error. This means that while it found the file, and it found the function, it's not returning anything! ("nil" is the Ruby way of saying "not anything".)

Make it return something

Inside the hello function, put a single line of string other than "hello".(Here we are simulating you making an honest mistake, so we can see what the error message looks like.)

def hello
  "hpllo?"
end

Save it and run the test again.

Watch it fail again.

You should now see the following error:

1) #hello the hello function says hello
Failure/Error: expect(hello).to eq("Hello!")

  expected: "Hello!"
      got: "hpllo?"

  (compared using ==)
# ./spec/hello_spec.rb:7:in `block (3 levels) in <top (required)>'

It is expecting "Hello!" but instead of that, it is getting "hpllo?". So let's fix that and run the test again.

def hello
   "Hello!"
end

Watch it pass.

The green dot on the top left represents that one out of three tests is passing.

Moving on to second test.

Similarly, let's define a method named greet

1) #hello the greet function says hello to someone
    Failure/Error:
      def greet
      end

    ArgumentError:
      wrong number of arguments (1 for 0)
    # ./lib/hello.rb:5:in `greet'
    # ./spec/hello_spec.rb:13:in `block (3 levels) in <top (required)>'

You now encounter the ArgumentError:. Meaning that our test code is passing one argument to our code but code is not expecting any arguments. Change the code and run the test.

def greet(name)
end

You should see different error message now.

1) #hello the greet function says hello to someone
    Failure/Error: expect(greet("Alice")).to eq("Hello, Alice!")

      expected: "Hello, Alice!"
          got: nil

      (compared using ==)
    # ./spec/hello_spec.rb:13:in `block (3 levels) in <top (required)>'

Let's make it pass.

def greet(name)
   "Hello, #{name}!"
end

This #{name} , is known as string interpolation. name is replaced by the string passed onto the function.

Save the code and run the test.

rspec
...

Finished in 0.00386 seconds (files took 0.12928 seconds to load)
3 examples, 0 failures

Lesson list