ryanb (owner)

Forks

Revisions

gist: 112284 Download_button fork
public
Public Clone URL: git://gist.github.com/112284.git
Embed All Files: show embed
quiz.rb #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# COMMUNITY CHALLENGE
#
# How would you test this Quiz#problem method? Only two rules:
#
# 1. The tests should fail if any part of the application breaks.
# For example: If "gets" is moved before "puts" then the tests should
# fail since that breaks the application.
#
# 2. You cannot change the Quiz class. But you can use whatever framework
# and tools you want for the tests. (RSpec, Cucumber, etc.)
#
# Note: The first rule used to be "no mocking" but I changed it. If you
# can accomplish the first rule with mocks then go ahead. I'm looking
# for the simplest/cleanest solution whatever that may be.
#
class Quiz
  def initialize(input = STDIN, output = STDOUT)
    @input = input
    @output = output
  end
  
  def problem
    first = rand(10)
    second = rand(10)
    @output.puts "What is #{first} + #{second}?"
    answer = @input.gets
    if answer.to_i == first + second
      @output.puts "Correct!"
    else
      @output.puts "Incorrect!"
    end
  end
end
 
require "test/unit"
 
class QuizTest < Test::Unit::TestCase
  def test_correct
    flunk # test the case of supplying correct answer here
  end
  
  def test_incorrect
    flunk # test the case of supplying incorrect answer here
  end
end
 
solutions.txt #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
SOLUTIONS
 
There are many ways to solve this problem. If you come up with more let me know
and I'll add them here.
 
Custom IO Class
 
  This was by far the most common solution. It involves creating a class which
  has its own "puts" method to record the output and a "gets" method to calculate
  the proper response based on that output.
  
  Overall this is an elegant solution. The only thing I don't care for is that
  it requires all logic to be set up front and the @quiz.problem call must
  happen at the end.
  
  Favorites:
  1. http://gist.github.com/112547 by matflores
  2. http://gist.github.com/112378 by ljsc
  3. http://gist.github.com/112309 by sandal
 
 
Mocking Methods
 
  This was originally against the rules because I was looking for other
  creative alternatives which mimicked the user at a higher level and cared
  little about the implementation. However, the mocking solution proved cleaner
  than I originally expected. It also provided the most helpful error messages
  when the app broke (if the order got switched, etc.).
  
  Like the previous solution the @quiz.problem is called at the end. It also has
  some dependencies on the implementation, specifically the "rand" method must
  be stubbed. IMO this is acceptable but might become an issue in more complex
  scenarios where more would need to be stubbed.
  
  Favorites:
  1. http://gist.github.com/112300 by intinig
  2. http://gist.github.com/112411 by jimweirich
 
 
Separate Thread or Process
 
  Here the Quiz#problem runs in a separate thread or process. I consider it to be
  a higher level test than the others because it is the closest to mimicking a real
  user. The @quiz.problem is called first and the test assertions happen live as it
  is running.
  
  I was hoping to see a few more experimentations along this line. You can see my
  take on the problem below which uses a separate generic class to handle the dirty
  work and leaves the test implementation very clean and self contained.
  
  Favorites:
  1. http://gist.github.com/112476 by ryanb
  2. http://gist.github.com/112326 by nimbletechnique