Welcome to the third chapter of the test driven development course.
And in the last chapter we talked about the core of the red green refactor pattern and practiced it
a couple of times together.
Now in this chapter we are going to learn to write trustworthy tests and and discover new scenarios.
And we will also learn about parameterized testing using the following technique.
We check if we have enough tests because right now we don't really know that.
So here we have the flight specifications class and we have two tests inside.
Booking reduces the number of seats and avoids overbooking.
Now let me open up the flight class and attach it side by side so that we can see both classes at the
same time.
Now, let me zoom out a bit.
I guess you can still follow along because this is just for a quick overview.
Now let me zoom a little bit in.
That's fine.
So is there any way to modify the book method that we have right here on the right side to behave unexpectedly
while the test still passes?
Let's see.
Let's just comment out the if statement that we have right here and also comment out the return null
and instead of returning null, we simply return a new overbooking error in any scenario, right?
So no matter what, you will always get that overbooking error.
Now that doesn't seem to be right.
Correct.
But let's just run the test and see if everything passes where you can see that all tests have passed.
And actually you can now tell that our tests are not trustworthy.
So how do we write tests in a way that such changes like we have done them here in the booking method
or in the book method, do actually result in a failure?
Because right now this test should fail.
We achieve this so we make them trustworthy by usually adding more tests.
So let's add one more test.
I will just increase the size so that you can follow along better.
Let's create in the flight specifications a new test.
So write down fact.
So a new attribute called fact.
And we create a public void Books flights successfully.
Now what we do is we create a new flight equals to new flight.
And the seat capacity is set to three again and we get an error object here flight or maybe we get an
error object, right?
It's nullable and we book that flight for yannick@tutorials.com and we book the flight for one person.
So we should not get an error and the error dot should dot be null.
So this is a single method.
So right now it will fail because we are always receiving an overbook error because we changed the actual
functionality of the book method.
So our tests.
Now let's right click and run the test.
It will fail.
And that's good.
That's good because now we have seen that there is again a mistake inside of the implementation.
So booking reduces the number passes.
But book flight successfully fails because we receive an error on That's wrong because everything should
work.
But we are getting that error because we have a wrong implementation inside of our book method.
So what we do now is we again return that null here that we have that way.
So let's save it.
Let's run the tests again.
Now you can see that this one is successful, but the other one is failing.
Right?
So avoids overbooking is not working anymore.
And for this, the only way to fix it is to now say if number of seats.
Right.
We just bring that in again and return that overbooking error in an overbooking scenario, save it,
run the tests again and we will now have a trustworthy test.
And that's pretty awesome.
So by implementing more tests around your scenario, you can increase the trustworthiness up to a maximum
level in the TDD approach.
What we just did was a technique called devil's advocate and it's like a game.
The game has two players, the devil's advocate and the tester, and a single player can play both roles.
However, Tester and devil's Advocate fight against each other for production code.
Devil's advocate wants the production code to misbehave, while the tester for sure wants to save the
production code from misbehaving and testers are only allowed to add or modify tests based on the game's
rules, testers are not allowed to change production code and devil's advocate is not allowed to change
tests.
It's the job of the devil's advocate to keep all tests green and passing, even if the tester adds a
failing test.
So devil's advocate should pass it.
And these are the game's instructions.
Imagine a scenario where you have written a test, made it pass, and refactor the code.
Now, as a tester, you should ensure that the tests you have written so far cover the edge cases as
well.
You switch your role to the devil's advocate and try to modify the production code to make it behave
wrong without causing the test cases to fail.
With the modifications you make, the production code should violate the intentions of the existing
test cases without breaking them.
Remember that the devil's advocate is not allowed to modify any test.
You can only change the production code.
The production code should end up incorrect, but its test should remain passing then.
You change your role to the tester again and add a new test to defeat the devil and defend the test
from such attacks next time.
Testers aren't allowed to modify the production code, so you finally switch your role to devil's advocate
again, since the devil's advocate has to keep all the tests passed.
You will have to pass the test and try to identify other edge cases with each attack of devil's advocate.
The tester gets stronger and stronger by each attack.
The tester realizes a weakness and adds a test that automatically defends the production code against
such an attack.
So let's play this game in practice now.