#100DaysOfCode in Python Transcripts
Chapter: Days 10-12: Testing your code with pytest
Lecture: Testing (simulating) the game end-to-end

Login or purchase this course to watch this video and the rest of the course contents.
0:00 Alright for the final two test methods that I actually want to run a whole game from end to end. And I'm going to use the same technique as before
0:09 because we're still stuck with this input method that requires us to input data which we don't have in an automated way of running test with pytest.
0:19 So I'm going to do a patch of the input again and I'm going to just simulate a whole game. So I'm going to enter 4, 22, 9, 4, and 6.
0:32 They're going to play a win scenario and I'm going to give it the input which is the requirement of the patch
0:38 but I'm also going to capture the standard out as I did before. So I make a game. And I need to give it a right answer to make sense of these numbers.
0:50 So in this scenario win but at the fifth attempt, which is 6. So the answer is 6. I call the game and assert that the game state
1:03 is underscore win equals true. Let's run this. Okay. So what it actually did, calling game, is it went through all these numbers
1:18 and when it got to the final one, the fifth attempt, it asserted answers true, so the win was set to true. And again, you can see in the call,
1:30 an actual look that when validate guess returns true, which is on the previous test, there is an intermediate variable win set to true
1:38 and it also sets the inner, or internal variable win, to true. And that's what we are asserting here. But what I'm also interested in
1:46 is how the output looks of the program. So I can just again do capfd, read out err, and you can also just call this with zero indexing
2:01 then you don't need the throw-away variable at all. And I have a bunch of expected states which I'm going to copy in.
2:10 Let's actually assimilate this program. So I have these steps I'm just going to hard code the answer for a minute, 6. So these are the steps.
2:23 So what the test is doing is pretty pretty cool. So I'm simulating 4, 22, which is not in range. 9, 4, 6. So here you see the typical program,
2:38 and that's what we are asserting here with these expected values. So 4 is too low, number not in range. 9 is too high, already guessed. 6 is correct.
2:47 Plus an additional statement of it took you three guesses. So let's reset this. Let's clean the output from capfd a little, with a list comprehension.
2:57 For line in out split by new line. Only take lines with one or more characters. So ignore blank lines basically.
3:12 And give me the strip lines. So I'm stripping off new lines. Alright. And then we can just match it line by line.
3:23 I can use a zip to look over two sequences. So you have line and expected in zip output and expected. So this will look over expected
3:36 and look over output in parallel. So the first value of output would match the first value in expected and etc.
3:47 Alright. Look at that. What's my coverage? 94 percent, very nice. So they're only a couple lines missing: 83, 87, 88
4:01 And 87 I'm okay with because this is just a calling code if this is called as a script, which we've done before, if I call it like this.
4:11 And line 83. Let's see if we can get to this scenario as well. So this is a lose scenario, where we tried it 5 times
4:19 and still did not assert the answer. So let's set up a filled scenario. Test, game, lose. That's going to follow the same signature as above.
4:36 But I need more stamps. So let's do a none, which should not count right away. 5, 9, 14, 11, 12, doesn't really matter because what I need to do now
4:48 is to give it an answer that's just totally different. So let's make a game. And the game answer is 13. So it's not in all my guesses.
5:00 But this also test that none doesn't count towards my guesses. So I can actually do 6 inputs and this would be the fifth guess.
5:10 So I'm actually getting here in the first place. Play the game. I won't win this game. And it should pass, right,
5:27 but the coverage should still be the same because I'm not hitting that line yet. I do. Yeah, I did. So just to recap, this was line 83,
5:37 which corresponds to this line. And what happened here, I played, actually what I forgot is that this plays the whole game.
5:44 When I launch game, it goes through all these outputs. And having guessed 5 times, and not asserting this answer, I did get to the L's block.
5:53 I can actually show that. If I turn on non-capture mode. See? It just prints the whole thing. 5's too low, 9 is too low, then I guessed 5 times.
6:03 Answer is 13. So I made it to this actual print statement. And that was the final thing to actually increase the coverage.
6:12 If you take main out, we have a 100% coverage of our tests. You still need to have a critical eye to your code and your tests
6:21 because one thing is to test it, but, for example, I can get a 100% on this earlier validation of the guesses, sorry, this one,
6:30 but here I made sure that I'm going into all the different kind of value errors. Actually let's do an experiment.
6:36 If I'm not doing the not-a-number test, would my coverage go down? Wow, look at that, how cool. So I took a test out
6:48 and now it's complaining that 35 and 36 are missing. And 35 36 is they should be a number, and that's the thing we just deleted.
6:57 So I had a string here, and that not-a-number should raise an exception. And coverage spotted that. So that's very cool,
7:04 that you can just pinpoint exactly which code is not being tested versus which code it is. But again, you still need to have a critical eye
7:11 of what you're testing. Because one thing is to have all your lines, some were called, but the other thing is how you call them.
7:17 What are you testing? Are you testing all the edge cases? So testing is an art in itself.

Talk Python's Mastodon Michael Kennedy's Mastodon