# Learning TDD With RSpec Part 2

This is part 2 of a planned 3 part series

### Introduction:

In [part 1](https://blog.edssemuwemba.com/learning-tdd-with-rspec), this was achieved;
1.  Initialising project
2. Writing a test for when nothing has been scanned

In part 2, this is going to be handled;
1.  Scanning of A
2. Scanning of B
3. Scanning of C
4. Scanning of D

Tests will be run using;
1.  `⎵ + t` : run entire test (`⎵` means the keyboard `space bar button`)
2.  `⎵ + l` : run last test
3.  `⎵ + s`: run nearest test

### Scanning of A:

Add another context to check for when `A` has been scanned. The file changes to this;

```ruby
class CheckOut
  def initialize(pricing_rules)

  end

  def total
    0
  end
end

RSpec.describe 'checkout' do
  context 'when nothing has been scanned' do
    it 'shows a total of zero' do
      pricing_rules = :Rule
      checkout = CheckOut.new(pricing_rules)
      total = checkout.total

      expect(total).to eq 0
    end
  end
  context 'when A has been scanned' do
    it 'shows the price of A' do

      expect(total).to eq 50
    end
  end
end
```
Run the test by pressing `⎵ + t`. We get this error;

```ruby
~
./bin/rspec spec/check_out_spec.rb

Randomized with seed 34364
.F

Failures:

  1) checkout when A has been scanned shows the price of A
     Failure/Error: expect(total).to eq 50

     NameError:
       undefined local variable or method `total' for #<RSpec::ExampleGroups::Checkout::WhenAHasBeenScanned "shows the price of A" (./spec/check_out_spec.rb:22)>
     # ./spec/check_out_spec.rb:24:in `block (3 levels) in <top (required)>'

Finished in 0.00256 seconds (files took 0.05539 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/check_out_spec.rb:22 # checkout when A has been scanned shows the price of A

Randomized with seed 34364


shell returned 1

Press ENTER or type command to continue

```
Modify the file to add the lines specifying what `total` is and define `pricing_rules`;

```ruby
class CheckOut
  def initialize(pricing_rules)

  end

  def total
    0
  end
end

RSpec.describe 'checkout' do
  context 'when nothing has been scanned' do
    it 'shows a total of zero' do
      pricing_rules = :Rule
      checkout = CheckOut.new(pricing_rules)
      total = checkout.total

      expect(total).to eq 0
    end
  end
  context 'when A has been scanned' do
    it 'shows the price of A' do
      pricing_rules = :Rule
      checkout = CheckOut.new(pricing_rules)
      total = checkout.total

      expect(total).to eq 50
    end
  end
end
```
When the test is run, as expected we get the error as shown below;

```ruby
./bin/rspec spec/check_out_spec.rb

Randomized with seed 5579
.F

Failures:

  1) checkout when A has been scanned shows the price of A
     Failure/Error: expect(total).to eq 50

       expected: 50
            got: 0

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

Finished in 0.00758 seconds (files took 0.0523 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/check_out_spec.rb:22 # checkout when A has been scanned shows the price of A

Randomized with seed 5579


shell returned 1

Press ENTER or type command to continue


```
A change needs to be made to the spec to include scanning of Item A.
This changes the file to be;

```ruby
 class CheckOut
   def initialize(pricing_rules)

   end

   def total
     0
   end
 end

 RSpec.describe 'checkout' do
   context 'when nothing has been scanned' do
     it 'shows a total of zero' do
       pricing_rules = :Rule
       checkout = CheckOut.new(pricing_rules)
       total = checkout.total

       expect(total).to eq 0
     end
   end
   context 'when A has been scanned' do
     it 'shows the price of A' do
       pricing_rules = :Rule
       checkout = CheckOut.new(pricing_rules)

       checkout.scan('A')
       total = checkout.total

       expect(total).to eq 50
     end
   end
 end
```

When `checkout.scan('A')` is added, we get this error;

```ruby
./bin/rspec spec/check_out_spec.rb

Randomized with seed 45438
.F

Failures:

  1) checkout when A has been scanned shows the price of A
     Failure/Error: checkout.scan('A')

     NoMethodError:
       undefined method `scan' for #<CheckOut:0x0000000130ca8448>
     # ./spec/check_out_spec.rb:26:in `block (3 levels) in <top (required)>'

Finished in 0.00187 seconds (files took 0.04966 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/check_out_spec.rb:22 # checkout when A has been scanned shows the price of A

Randomized with seed 45438


shell returned 1

Press ENTER or type command to continue

```

Add the method: `scan(item)` to `CheckOut` class to fix this error;

```ruby
class CheckOut
  def initialize(pricing_rules)

  end

  def total
    0
  end

  def scan(item)

  end
end
```

Now we are back to the previous error when the test is run;
```ruby
./bin/rspec spec/check_out_spec.rb

Randomized with seed 56370
.F

Failures:

  1) checkout when A has been scanned shows the price of A
     Failure/Error: expect(total).to eq 50

       expected: 50
            got: 0

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

Finished in 0.00768 seconds (files took 0.04974 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/check_out_spec.rb:26 # checkout when A has been scanned shows the price of A

Randomized with seed 56370


shell returned 1

Press ENTER or type command to continue

```
To fix this error, we make three changes to the `CheckOut` class as below;
```ruby

 class CheckOut
   def initialize(pricing_rules)
     @total = 0
   end

   def total
     @total
   end

   def scan(item)
     @total = 50
   end
 end

```
Now when the test is run, all the current two tests will pass successfully;
```ruby
./bin/rspec spec/check_out_spec.rb

Randomized with seed 4857
..

Finished in 0.00201 seconds (files took 0.04948 seconds to load)
2 examples, 0 failures

Randomized with seed 4857


Press ENTER or type command to continue

```

### Scanning of B:

Add another context to check for when `B` has been scanned. 
Add the context to the `RSpec.describe 'checkout'` block.

The file changes to this;
```ruby
 RSpec.describe 'checkout' do
   context 'when nothing has been scanned' do
     it 'shows a total of zero' do
       pricing_rules = :Rule
       checkout = CheckOut.new(pricing_rules)
       total = checkout.total

       expect(total).to eq 0
     end
   end
   context 'when A has been scanned' do
     it 'shows the price of A' do
       pricing_rules = :Rule
       checkout = CheckOut.new(pricing_rules)

       checkout.scan('A')
       total = checkout.total

       expect(total).to eq 50
     end
   end
   context 'when B has been scanned' do
     it 'shows the price of B' do
       pricing_rules = :Rule
       checkout = CheckOut.new(pricing_rules)

       checkout.scan('B')
       total = checkout.total

       expect(total).to eq 30
     end
   end
 end

```

When `⎵ + s` is pressed on the keyboard to only run this new test, the following error is displayed;

```ruby
./bin/rspec spec/check_out_spec.rb:36
Run options: include {:locations=>{"./spec/check_out_spec.rb"=>[36]}}

Randomized with seed 53332
F

Failures:

  1) checkout when B has been scanned shows the price of B
     Failure/Error: expect(total).to eq 30

       expected: 30
            got: 50

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

Finished in 0.00643 seconds (files took 0.0565 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/check_out_spec.rb:37 # checkout when B has been scanned shows the price of A

Randomized with seed 53332


shell returned 1

Press ENTER or type command to continue
```
To fix this, make changes to the `scan` method in the `CheckOut` class;
```ruby
class CheckOut
  def initialize(pricing_rules)
    @total = 0
  end

  def total
    @total
  end

  def scan(item)
    if item == 'A'
      @total = 50
    elsif item == 'B'
      @total = 30
    end
  end
end
```
Now when press ` ⎵ + l` to run the last test, the test for scanning `B` now passes as well;

```ruby
./bin/rspec spec/check_out_spec.rb:40
Run options: include {:locations=>{"./spec/check_out_spec.rb"=>[40]}}

Randomized with seed 59538
.

Finished in 0.00059 seconds (files took 0.05165 seconds to load)
1 example, 0 failures

Randomized with seed 59538


Press ENTER or type command to continue
```
### Scanning of C:

Add another context to check for when `C` has been scanned. 
Add the context to the `RSpec.describe 'checkout'` block.

This is the context;

```ruby
   context 'when C has been scanned' do
     it 'shows the price of C' do
       pricing_rules = :Rule
       checkout = CheckOut.new(pricing_rules)

       checkout.scan('C')
       total = checkout.total

       expect(total).to eq 20
     end
   end
```

When ` + s` is pressed to run this new test, this error results;
```ruby
./bin/rspec spec/check_out_spec.rb:59
Run options: include {:locations=>{"./spec/check_out_spec.rb"=>[59]}}

Randomized with seed 51710
F

Failures:

  1) checkout when C has been scanned shows the price of C
     Failure/Error: expect(total).to eq 20

       expected: 20
            got: 0

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

Finished in 0.00602 seconds (files took 0.05125 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/check_out_spec.rb:52 # checkout when C has been scanned shows the price of C

Randomized with seed 51710


shell returned 1

Press ENTER or type command to continue

```
To fix this, make changes to the `CheckOut` class.

Do a check for `item C` like so;

```ruby
 class CheckOut
   def initialize(pricing_rules)
     @total = 0
   end

   def total
     @total
   end

   def scan(item)
     if item == 'A'
       @total = 50
     elsif item == 'B'
       @total = 30
     elsif item == 'C'
       @total = 20
     end
   end
 end

```

And now when the test is run, it should be pass;

```ruby
./bin/rspec spec/check_out_spec.rb:59
Run options: include {:locations=>{"./spec/check_out_spec.rb"=>[59]}}

Randomized with seed 2878
.

Finished in 0.00068 seconds (files took 0.05424 seconds to load)
1 example, 0 failures

Randomized with seed 2878


Press ENTER or type command to continue

```
### Scanning of D:

Add another context to check for when `D` has been scanned. 
Add the context to the `RSpec.describe 'checkout'` block.

This is the context;

```ruby
   context 'when D has been scanned' do
     it 'shows the price of D' do
       pricing_rules = :Rule
       checkout = CheckOut.new(pricing_rules)

       checkout.scan('D')
       total = checkout.total

       expect(total).to eq 15
     end
   end
```

When ` + s` is pressed to run this new test, this error results;
```ruby
./bin/rspec spec/check_out_spec.rb:72
Run options: include {:locations=>{"./spec/check_out_spec.rb"=>[72]}}

Randomized with seed 61671
F

Failures:

  1) checkout when D has been scanned shows the price of D
     Failure/Error: expect(total).to eq 15

       expected: 15
            got: 0

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

Finished in 0.00622 seconds (files took 0.0561 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/check_out_spec.rb:65 # checkout when D has been scanned shows the price of D

Randomized with seed 61671


shell returned 1

Press ENTER or type command to continue
```
To fix this, make changes to the `CheckOut` class.

Add an `else` to check for item `D`;

```ruby
 class CheckOut
   def initialize(pricing_rules)
     @total = 0
   end

   def total
     @total
   end

   def scan(item)
     if item == 'A'
       @total = 50
     elsif item == 'B'
       @total = 30
     elsif item == 'C'
       @total = 20
     else 
       @total = 15
     end
   end
 end

```

And now when the test is run, it should be pass;

```ruby
./bin/rspec spec/check_out_spec.rb:72
Run options: include {:locations=>{"./spec/check_out_spec.rb"=>[72]}}

Randomized with seed 38120
.

Finished in 0.00059 seconds (files took 0.05152 seconds to load)
1 example, 0 failures

Randomized with seed 38120


Press ENTER or type command to continue

```

### Conclusion:

This concludes part 2.

In part 3, this will handled;

1.  refactoring to make the code better.
2. taking the pricing rules into account

Shout out to [Rob](https://twitter.com/purinkle)  for his immense assistance on this and making it easy to comprehend.
