Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Start a free Basic trial
to watch this video
Chris shows you how to take some legacy code and figure out exactly what tests are needed
-
0:00
[MUSIC]
-
0:04
Hey, everyone.
-
0:05
It's Chris again.
-
0:06
Previously, I talked about writing your first test by going over how I like to
-
0:10
create testing scenarios.
-
0:12
Now, that we've learned a little bit about how to go from scenario to working test.
-
0:15
Let's tackle, one of the bigger problems that developers will face.
-
0:18
Writing tests for code that already exists.
-
0:22
Through much of this course I
-
0:23
will be using code samples from the Open CFP Project.
-
0:26
It's an open sourced web application written in PHP that helps
-
0:30
programming conference organizers manage the top submissions that come in.
-
0:34
Much like the cobbler's children in the story of old.
-
0:36
Open CFP does not have enough tests.
-
0:38
Let's see if we can fix that by finding some code that doesn't already have
-
0:42
tests for it.
-
0:43
After running my tests with the code coverage option,
-
0:46
I can identify thing that need some more test loving.
-
0:49
Code coverage simply means, when you run the tests,
-
0:52
identify all the code that got executed during the tests.
-
0:55
Typically, you aim for a high level of code coverage.
-
0:58
Ideally, you want 100% coverage.
-
1:00
But anything 90% and above is quite good.
-
1:03
It still means you have code that you haven't tested though.
-
1:06
In Open CFP, we have an object that represents speakers.
-
1:09
At the time I generated the coverage report, we're at 52.88% coverage.
-
1:12
That's terrible.
-
1:14
Let's pick one method inside the speaker object that has no tests and write one.
-
1:20
We might also have an opportunity to refactor the code in question because it
-
1:23
is difficult to test.
-
1:24
Do not underestimate how often you will have to
-
1:27
do this if you are adding tests to a project that is already under way.
-
1:32
In this one I'm gonna talk a little bit about how you identify what tests to
-
1:36
write for existing code.
-
1:37
Normally, it is nice when you're started on a brand new project that you're able to
-
1:40
write tests for every little bit of code that you write, right from the beginning.
-
1:44
But often that's not the case.
-
1:45
Often times you have tests for
-
1:47
existing code and you'll need to get more coverage for that particular bit of code.
-
1:52
And by coverage I mean, making sure you have enough test that every line of
-
1:55
code inside a particular method is getting tested.
-
1:58
So, I'm gonna show you an object from my Open CFP project, that represents
-
2:03
information about a speaker, and we're gonna look at one method inside there.
-
2:07
And, assuming that we have no tests for
-
2:09
it already, how will we identify exactly the type of test that we need?
-
2:12
So, I'm gonna open this up.
-
2:13
And we're gonna go.
-
2:14
I'm just gonna use Vim here and tell it to find me, where it says function update.
-
2:18
So this is the update method where we're gonna update a speaker record.
-
2:20
As you can see, we start off with here, in the doc block above we're showing,
-
2:25
what parameters we're gonna be passing in.
-
2:26
We have speaker details and then we have the existing details.
-
2:29
The purpose of this bit of code is to say, when I've gone into a person's account and
-
2:34
they're updating their own information, we wanna determine whether or
-
2:38
not we need to update the existing information in the database.
-
2:41
So, you know, this is always the thing that asked me, what am I supposed to test?
-
2:44
I think,there's actually one really simple rule that you need to follow.
-
2:48
Every single conditional statement in a method needs a test.
-
2:51
So, if we are looking at this actual code,
-
2:53
we can identify some bits of code that need attention.
-
2:56
For example, we would need to write a test where,
-
2:58
remove the old photo if a new one has been uploaded, so use unlink.
-
3:01
We are also doing a comparison that says, if any of these items are different,
-
3:06
if anything between the existing record in the system and what the user wants to
-
3:10
update, there's any difference, then we wanna do an update statement.
-
3:13
Also, have a condition thing here that says, if you know,
-
3:15
we're checking to see, do we have an existing record that we need to update?
-
3:19
So, we're doing a SQL query, hitting the database.
-
3:22
We then do a comparison here, conditional statement if we get back a speaker count
-
3:26
and the speaker count is one we're gonna have to do some updates and on and
-
3:30
on we go, we also have here if the speaker count.
-
3:33
If we don't have any speaker information then we need to create a new record so
-
3:35
we're doing an insert.
-
3:37
So that's basically it.
-
3:39
So how many numbers is this?
-
3:41
If we go back and count, I believe the number is seven, so,
-
3:45
this means at a minimum, we would need at least seven different tests.
-
3:48
We wanna make sure that every conditional statement is covered by a line of code.
-
3:52
But however, there is one bit of code that we would need to refactor in
-
3:55
order to write a nice unit test.
-
3:56
It's this little section right here by removing old photo.
-
3:59
As you can see, we're doing an action on the file system.
-
4:01
We're using unlink,
-
4:02
which is a command that PHP can use to actually remove a file.
-
4:05
This is problematic for two reasons.
-
4:07
For number one, during a test you don't wanna actually ever destroy anything
-
4:10
that's in production.
-
4:11
So, you can see that we, we are actually going to physically delete the file.
-
4:15
And secondly, this is a dependency inside the object itself,
-
4:18
inside the method that we need to unlink it.
-
4:21
So, if I were to refactor this bit of code to make it easier to test, I would
-
4:25
take this bit of code that is checking to see if the speaker photo is different.
-
4:29
I would create some method calling delete speaker photo and
-
4:32
then in whatever code is actually calling the update method.
-
4:36
Right after it, we would call some sort of method.
-
4:39
We would probably call it like clean up photos or something.
-
4:41
So, it's very gentle introduction to this,
-
4:43
as you can see the unlinking of the file system is, is bad to doing the test.
-
4:48
If I were to do it there are several tools available to us that would let us
-
4:51
create virtual file systems for testing purposes.
-
4:54
The most common is called, VFS Stream.
-
4:57
I'll put a link in the teacher's notes so you can kinda get an idea of how it works.
-
5:00
Basically, it lets us create a file system that's in memory.
-
5:03
So, instead of writing to the file system,
-
5:04
we're actually writing to a phantom file system that's in memory and
-
5:07
then when the test finishes that little file system goes away.
-
5:11
And then we don't, we don't have to actually touch or
-
5:12
disturb anything in our existing application.
-
5:14
So, to recap my own personal strategy for
-
5:17
figuring out what tests need to be written for existing code.
-
5:19
You just need to look at the code, look at all the conditional statements inside it,
-
5:22
figure every conditional statement is at least one test that you
-
5:25
need to trigger that conditional statement.
-
5:28
And also you need to take a look and
-
5:29
see are there any dependencies inside that you need to move out
-
5:32
from inside the method into its own standalone thing for testing purposes.
-
5:37
We already have some existing tests, so
-
5:39
luckily, we don't have to write tests for everything inside this method.
-
5:42
In our next video, I'm going to show you how I picked one section of the code that
-
5:46
had no testing coverage, created the testing scenario and
-
5:49
converted the scenario into a working test.
-
5:51
See you next time.
You need to sign up for Treehouse in order to download course files.
Sign up