On 9/28/2013 12:52 AM, melw...@gmail.com wrote:
[How can I test...]

import random

intro = 'I have chosen a number from 1-10'
request = 'Guess a number: '
responseHigh = "That's too high."
responseLow  = "That's too low."
responseCorrect = "That's right!"
goodbye = 'Goodbye and thanks for playing!'

print(intro)

def main():
     guessesTaken = 0
     number = random.randint(1, 10)
     while guessesTaken < 5:
         print(request)
         guess = input()
         guess = int(guess)

         guessesTaken = guessesTaken + 1

         if guess < number:
             print(responseLow)

         if guess > number:
             print(responseHigh)

         if guess == number:
             break

     if guess == number:
             guessesTaken = str(guessesTaken)
             print(responseCorrect + '! You guessed my number in ' + 
guessesTaken + ' guesses!')

     if guess != number:
         number = str(number)
         print(goodbye + ' The number I was thinking of was ' + number)

if __name__ == '__main__':
     main()

To expand on Dave's answer, I would refactor main() as below.

Note 1. I add 'allowed' so you can easily change the number or let the user decide the difficulty. One can always guess right in at most 4 tries.

Note 2. I am presuming that you are using 3.x.

allowed = 5

def getguess(target, allowed):
  tries = 0
  while tries < allowed:
    tries += 1
    guess = int(input(request))
    if guess < target:
      print(response_low)
    elif guess > target:
      print(response_high)
    else:
      return guess, tries

def main(target)
  guess, tries = getguess(target, allowed)
  if guess == number:
print(responseCorrect + '! You guessed my number in ' + tries + ' guesses!')
  else:
    print(goodbye + ' The number I was thinking of was ' + number)

if __name__ == '__main__':
  main(random.randint(1, 10))

To test a function, you must be able to control inputs and access outputs. Unfortunately, this makes testing simple beginner programs that turn user input and random numbers input into screen output harder, in a way, than testing complicated math functions, such as one that approximates the derivative of a function as a point.

One way to control user input for getguess is to put something like the following (untested) in your test module. (Ignore print for the moment.)

class IntInput:
  "Replace input() that should return int as string."
  def __init__(self, ints, print=None)
    "Ints must be a sequence of ints"
    self.i = -1  # so 0 after first increment
    self.ints = ints
    self.print = print
  def input(prompt):
    "Maybe save prompt, return str(int)."
    if self.print:
      self.print(prompt)
    i = self.i + 1
    self.i = i
    return str(self.ints[i])

In test methods, inject a mock input into the tested module with something like
        g.input = IntInput((5,3,2,1)).input
where the sequence passed is appropriate for the target and the response you want. This will be sufficient to test most of the operation of getguess.

(I am aware that some would say that IntInput should be a context manager with an exit method that restores g.input. I do not think that this complication is needed for this post.)

To test the getguess prompts and main output, collect output lines with something like

class Screen:
  def __init__(self):
    self.lines = []
  def print(self, line):
    self.lines.append(line)

  screen = Screen()
  g.input = IntInput((5,3,2,1), screen.print).input
  # Test that screen.lines is as it should be.
  # Be careful that actual and expected both have
  # or both do not have terminal \n.

For testing main, in test_xxx methods,
    screen = Screen
    g.print = screen.print
    # test screen.lines in

Another approach is to replace sys.stdin/out as is done in test.support.capture_stdin/out, but the latter are considered internal functions not for general use, and this method seems more complicated.

random and random.randint could be mocked, but this in not needed for this program with the randint call moved out of main().

---
Terry Jan Reedy


--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to