Test Your Code
In this lesson, you’ll dip your toes into testing your code. To learn more on this topic, check out:
00:00 Test Your Code Repeatedly. Running your code while you are developing it is a great way to ensure that the code does what you expect. Organizing your code and functions opens up another avenue for staying in control: unit tests. You can add tests that check each of your functions.
00:18 You won’t do much more automated testing in this course, but this example will show you one way to get started. Feel free to expand the tests to the rest of the code.
00:29 Test-driven development is a popular practice that focuses on automated testing. If you practice TDD, you’ll write tests before you write code. To learn more about this, check out this Real Python tutorial.
00:45
The great feature of unit testing is that you can test each part of your code in isolation. To see an example, you’ll create a doctest for show_guess()
.
00:55 A doctest is a special unit test integrated into your documentation. You write doctests inside docstrings. A docstring is a comment written as a string on the first line inside a function definition.
01:09 It’s good practice to include these, as they give information to Python’s help system as well as tools such as editors and auto-generated documentation systems.
01:18
If you include a code example prefixed by the Python REPL prompt (>>>
) inside the docstring, then you can use the doctest
module to test the function.
01:27
To see this in action, add the code seen on-screen to show_guess()
.
01:55
The docstring is a comment, and it won’t affect how the program runs. But writing this documentation has two immediate advantages. It helps developers, including yourself, understand how to use the function, and it can automatically be tested with doctest
.
02:12
To test that the docstring example works, you can call doctest
.
02:21
Here you include the -v
flag, which triggers verbose mode. Without this, you wouldn’t see anything unless you had a failing test. In practice, that’s often what you want, but the verbose mode can be instructive to look at, particularly when you first start using doctest
.
02:38
Here you can see that doctest
found the example that you added to show_guess()
. It picks up the call to show_guess()
comparing CRANE and SNAKE, as well as the output that you expect.
02:49
Adding a few doctests is a great way to get started with testing. Take a look at this Real Python tutorial to learn more about the features of doctest
.
03:00
Sometimes you may want to change your code to make it easier to test. You’ve already seen how refactoring wyrdl.py
to use functions made it possible to add a doctest. However, if you were to add a similar test to get_random_word()
, then you’d quickly run into a few challenges.
03:16
The return value of the function is random, so which value should be expected? The function implicitly depends on wordlist.txt
, so if you change that file, then the return value of the function will change.
03:30
These challenges hint that you could improve the implementation of get_random_word()
. One way to do this is to read the word list outside the function and pass it in as a parameter. To achieve this, alter the function as seen on-screen.
03:46
Add word_list
as an argument. Remove the line which reads the file,
03:55
and alter the for
loop to iterate over the list that will be passed in.
04:03
Here, you assume that word_list
will be a list of strings that’s passed to get_random_()
. If you do this, then you need to update main()
correspondingly, with lines which should look familiar, as they’re very similar to the ones that were just removed from get_random_word()
.
04:35
You’ve moved the responsibility of reading the word list to main()
. The advantage of this is that get_random_word()
has a clearer purpose and can be tested more easily. You can now add the following doctest, which checks that get_random_word()
correctly filters out words in the word list with the wrong length or with non-letter characters.
05:08
Here, "worm"
should be rejected since it only has four letters, and "it'll"
should be rejected because it contains an apostrophe, which isn’t a letter.
05:16
This leaves only "snake"
as an alternative in the given word list. The function should therefore always return this word in uppercase.
05:27 Once more, you can run doctests using the command seen earlier on, and hopefully you should see two tests that pass.
05:37 Testing random results is hard. One possible work-around is to set the seed of the random number generator. By setting a fixed random seed, you get deterministic randomness.
05:50
In this example, WYRDL
is chosen at random, but get_random_word()
will always return this as long as the seed is set to 42
immediately before it’s called.
06:01 Another possibility is using a different and more powerful testing framework. For example, with pytest, you can write more complex assertions as seen on-screen.
06:11 Here you’re making sure only that the random word is one of the words in the original list. On-screen, you can see this test being run.
06:26 If you want to learn more about pytest, Testing Your Code With Pytest will get you on the right path, including how to install it and how to create and run tests.
06:37 Adding tests to your code is an important exercise. It will make you more conscious about the assumptions you make, and it will help you debug your code when it’s not working as expected. To keep the scope focused, you won’t work on any more tests in this course, but feel free to add them yourself. At this point, the game should be running, and it has some tests present.
07:00 Remember that if you need a pointer in the right direction, the course materials include the code at this state so you can compare should you need to do so. But in the next section of the course, you can learn how to improve the look and feel of the game even though it runs in the terminal.
Become a Member to join the conversation.