I wrote a test-driven FizzBuzz program using the standard library doctest.
http://docs.python.jp/2/library/doctest.html (Begin quote) The doctest module looks for text that looks like an interactive Python session, executes the contents of the session, and sees if it behaves exactly as it is written. doctest is often used for the following purposes.
Check that the contents of the docstring are up-to-date by verifying that all of the interactive execution examples in the module's docstring (documentation string) work as written. Regression testing is achieved by verifying that the interactive execution examples in the test file or test object work as expected. You can write a tutorial document for a package that uses a lot of input / output examples. A document can be a "readable test" or a "executable document", depending on whether you focus on I / O examples or commentary. (End of citation)
doctest seems to be an excellent tool that can be used for regression testing while checking documents (comments). I have no choice but to try this.
http://www.atmarkit.co.jp/ait/articles/1403/05/news035.html (Begin citation (headline only)) [1] Write test code that fails [2] Write the code to be tested so that the test changes from failure to success [3] Add test code that causes the test to fail [4] Write the code to be tested so that the test changes from failure to success [5] Refactor the test with success (End of citation)
This time, we will follow this method.
I decided the specifications appropriately. Function name: fizzbuzz (n) function: If the input value n is a multiple of 3, the string'Fizz' is returned and If the input value n is a multiple of 5, the string'Buzz'is returned and If the input value n is a multiple of 15, it returns the string'FizzBuzz' and Other than that, a function that outputs an integer n.
n must be an integer represented by an integer type, a long integer type, or a floating point number type. (For floating point minority type, the fractional part must be 0.) If a small number is entered, an InputError exception will be returned.
First of all, temporary implementation
def fizzbuzz(n):
'''
If the input value n is a multiple of 3'Fizz'Returns the string
If the input value n is a multiple of 5'Buzz'Returns the string
If the input value n is a multiple of 15'FizzBuzz'Returns the string
Other than that, a function that outputs an integer n.
Example:
>>> fizzbuzz(3)
'Fizz'
n must be an integer represented by an integer type, a long integer type, or a floating point number type.
(For floating point minority type, the fractional part must be 0.)
If a small number is entered, InputError will be returned.
'''
return 'Fizz'
if __name__ == '__main__':
import doctest
doctest.testmod()
Run (-v is an option for detailed output). If you do not add -v, the information will be output only when the test fails.
python fizzbuzz_doctest.py -v
In this state, ok comes out.
Try adding a test case
>>> fizzbuzz(5)
'Buzz'
The following error is output.
File "fizzbuzz_doctest.py", line12, in __main__.fizzbuzz
Failed example:
fizzbuzz(5)
Expected:
'Buzz'
Got:
'Fizz'
1 items had no tests:
__main__
Modify as follows.
if (n%3) == 0:
return 'Fizz'
elif (n%5) == 0:
return 'Buzz'
Repeating the above [1]
Repeating the above [2]
Exception testing seems to require starting with Traceback. Also, you can omit the middle line with ....
>>> fizzbuzz(5.5)
Traceback (most recent call last):
...
ValueError: n must be integer. n: 5.500000
# coding: utf-8
def fizzbuzz(n):
'''
If the input value n is a multiple of 3'Fizz'Returns the string
If the input value n is a multiple of 5'Buzz'Returns the string
If the input value n is a multiple of 15'FizzBuzz'Returns the string
Other than that, a function that outputs an integer n.
Example:
>>> fizzbuzz(3)
'Fizz'
>>> fizzbuzz(36)
'Fizz'
>>> fizzbuzz(5)
'Buzz'
>>> fizzbuzz(50)
'Buzz'
>>> fizzbuzz(15)
'FizzBuzz'
>>> fizzbuzz(45)
'FizzBuzz'
>>> fizzbuzz(2)
2
>>> fizzbuzz(49)
49
n must be an integer represented by an integer type, a long integer type, or a floating point number type.
(For floating point minority type, the fractional part must be 0.)
If a small number is entered, ValueError will be returned.
>>> fizzbuzz(1.0)
1
>>> fizzbuzz(5.0)
'Buzz'
>>> fizzbuzz(5.5)
Traceback (most recent call last):
...
ValueError: n must be integer. n: 5.500000
'''
if n != int(n):
raise ValueError( 'n must be integer. n: %f' % n )
n = int(n)
if (n%15) == 0:
return 'FizzBuzz'
elif (n%3) == 0:
return 'Fizz'
elif (n%5) == 0:
return 'Buzz'
else:
return n
if __name__ == '__main__':
import doctest
doctest.testmod()
It seems that the final code can be obtained by refactoring while ensuring the operation by testing.
For example, you can make the following changes: In order to reduce the reference cost of the if statement, create a list whose elements are the remainder divided by 15 of each of 1 to 15 in advance, and determine the character string to be returned by referring to this list.
'''
if (n%15) == 0:
return 'FizzBuzz'
elif (n%3) == 0:
return 'Fizz'
elif (n%5) == 0:
return 'Buzz'
else:
return n
'''
fizzbuzz_list = []
for i in range(15):
if (i%15) == 0:
fizzbuzz_list.append('FizzBuzz')
elif (i%5) == 0:
fizzbuzz_list.append('Buzz')
elif (i%3) == 0:
fizzbuzz_list.append('Fizz')
else:
fizzbuzz_list.append(0)
r = int(n%15)
return fizzbuzz_list[r] if fizzbuzz_list[r] else n
You can perform a regression test with the following command without writing a new test.
python fizzbuzz_doctest.py -v
Let's change the algorithm further.
'''
if (n%15) == 0:
return 'FizzBuzz'
elif (n%3) == 0:
return 'Fizz'
elif (n%5) == 0:
return 'Buzz'
else:
return n
fizzbuzz_list = []
for i in range(15):
if (i%15) == 0:
fizzbuzz_list.append('FizzBuzz')
elif (i%5) == 0:
fizzbuzz_list.append('Buzz')
elif (i%3) == 0:
fizzbuzz_list.append('Fizz')
else:
fizzbuzz_list.append(0)
'''
fizzbuzz_list = ['FizzBuzz', 0, 0, 'Fizz', 0, 'Buzz', 'Fizz', 0, 0, 'Fizz', 'Buzz', 0, 'Fizz', 0, 0 ]
r = n%15
return fizzbuzz_list[r] if fizzbuzz_list[r] else n
You can run the regression test with the following command as before.
python fizzbuzz_doctest.py -v
Not only the code but also the documentation is complete.
# coding: utf-8
def fizzbuzz(n):
'''
If the input value n is a multiple of 3'Fizz'Returns the string
If the input value n is a multiple of 5'Buzz'Returns the string
If the input value n is a multiple of 15'FizzBuzz'Returns the string
Other than that, a function that outputs an integer n.
Example:
>>> fizzbuzz(3)
'Fizz'
>>> fizzbuzz(36)
'Fizz'
>>> fizzbuzz(5)
'Buzz'
>>> fizzbuzz(50)
'Buzz'
>>> fizzbuzz(15)
'FizzBuzz'
>>> fizzbuzz(45)
'FizzBuzz'
>>> fizzbuzz(2)
2
>>> fizzbuzz(49)
49
n must be an integer represented by an integer type, a long integer type, or a floating point number type.
(For floating point minority type, the fractional part must be 0.)
If a small number is entered, ValueError will be returned.
>>> fizzbuzz(1.0)
1
>>> fizzbuzz(5.0)
'Buzz'
>>> fizzbuzz(5.5)
Traceback (most recent call last):
...
ValueError: n must be integer. n: 5.500000
'''
if n != int(n):
raise ValueError( 'n must be integer. n: %f' % n )
n = int(n)
fizzbuzz_list = ['FizzBuzz', 0, 0, 'Fizz', 0, 'Buzz', 'Fizz', 0, 0, 'Fizz', 'Buzz', 0, 'Fizz', 0, 0 ]
r = n%15
return fizzbuzz_list[r] if fizzbuzz_list[r] else n
if __name__ == '__main__':
import doctest
doctest.testmod()
It seems to be easy to use because you can test and create documents at once. It has been pointed out that the code becomes difficult to read because the comment becomes long, but the two advantages of leaving the document are better maintainability and the quality can be guaranteed by executing the regression test are greater. feel like.
Recommended Posts