Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Parameterizing Your Tests

00:00 In the previous lesson, I showed you fixtures and monkey patches. In this lesson, I’ll introduce you to parameterizing your tests. There’s a special mark in pytest called parametrize.

00:13 It can be used to consolidate tests that are similar but use different data.

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.

00:31 Say it with me: parametrize.

00:37 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.

01:27 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.

02:00 And the last two are not. This forms a bit of a pattern, and you might ask yourself, is there another way of doing this? You’re probably ahead of me already. Of course there is.

02:13 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.

03:02 You can get quite complicated if you so desire.

03:09 The string ("") argument to the parametrize decorator actually can indicate more than one fixture. On line 10, I’ve defined two input values and an expectation.

03:20 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.

03:37 If you look closely at the data, it has a problem. I’ve done that on purpose so you can see the output. Going to go into the right directory on the bottom here … running the tests.

03:53 Let me just scroll back up.

03:57 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 timedelta of -1 days.

04:25 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.

04:41 I’ve covered the core of pytest to get you going. There are other bits out there if you want to dive deeper. Next up, I’ll summarize the course and point you at some useful plugins for pytest.

Avatar image for Andrea Fantasia

Andrea Fantasia on Aug. 22, 2022

Simplified is_palindrome() definition:

def is_palindrome(s):
    s = s.replace(' ', '').lower()
    return s[::] == s[::-1]
Avatar image for Ranudar

Ranudar on April 11, 2023

I find parametize in my dictionary (leo.org / Merriam Webster).

Avatar image for Ranudar

Ranudar on April 11, 2023

parametrize (damn you autocorrect).

Become a Member to join the conversation.