Parameterizing Your Tests
00:20 All right. I know that animation is a bit overboard, but I did want to point out that this isn’t a real word, and it isn’t spelled the way you expect. You have to spell it the pytest way for it to work.
Up until now, all the tests have been rather artificial. This time around, I’ve written some actual code to test. The function under test is called
is_palindrome() and tests if a string is a palindrome.
00:48 That’s anything that is the same forwards and backwards, like the word noon. Fancier palindromes usually ignore spaces and capitalization, allowing you to get things like a man a plan a canal Panama. I’ll wait here while you verify it for yourself.
01:06 This code first removes any spaces, then converts everything to lowercase. It then splits the string in half and has two cases, an even number of characters and an odd number of characters. In both cases, it figures out the left and right half of the string—in the odd case, ignoring the character in the dead center.
Then the left side of the string is compared with the reverse of the right side of the string. That
::-1 slice is a shortcut for reversal. Great. I’ve got the function in hand. Let’s write some tests.
01:45 First I’ll do it with some test functions, no parameters yet. I have six tests here, each of which call my function with a variety of data. The first four are palindromes, under our ignore spaces and capitalization rules.
This code tests the same thing, but uses the
parametrize mark. This mark is creating an in-place fixture for you. The mark takes two arguments: the name of the fixture, which like all fixtures becomes an argument to the test function, and the mark’s second argument is the data. Essentially, this has reduced the six test cases from before into just two tests: the case and the is not case using
parametrize to feed data into the two tests.
02:47 I’m not sure whether writing like this makes it more or less clear than previous, but I think it’s because I’ve done it in line. Declaring the data somewhere higher up in the file as a variable would probably make it a lot easier to read. This is actually a bit of a simple case.
The data then is a list of tuples, each having two input values and an expected value. This pattern is really, really common when you write tests. Even when I write things in the standard library
unittest world, I tend to have big lists of data in exactly this format.
This is where pytest rules. The output here is significantly more helpful than the standard library’s equivalent. Because of the use of
parametrize, pytest is able to tell exactly which piece of data causes the failure. It shows you the value of
a, the value of
b, and the value of
expected, and it shows you exactly what went wrong with the assertion. In this case,
a - b should result in a
I spent a lot of time trying to hunt down exactly this kind of problem with my tests in the standard library, when I’ve used
setup or something similar to create a large list of data and expected results. This is a much better way of doing things.
Become a Member to join the conversation.