This course will be retired on June 1, 2025.
Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Preview
Start a free Courses trial
to watch this video
There are many tactics for testing units independently from the rest of the code or system.
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign up
Most classes have to use other classes
in some way in order to do their job.
0:04
At the beginning of this
course we learned that unit
0:09
testing focuses on testing
a single unit of code.
0:12
Independent from the rest of the system.
0:15
When a test fails we need to
know why it failed, and that
0:18
the failure was caused by the unit being
tested and not by code in some other unit.
0:21
So how do we write a unit test for
a class if it depends on another class?
0:26
We should strive to test each unit
independently from all of their units.
0:32
This is probably the most
difficult aspect of unit testing.
0:36
There are many ways to achieve this goal.
0:41
Following good object-oriented design
principles when designing software is
0:43
the first step to making this
level of unit test possible.
0:48
In object-oriented design,
0:52
we strive to reduce the amount of concrete
coupling there is between classes.
0:53
There are many patterns and
0:58
best practices that can help In fact,
too many to cover in this course.
1:00
So, we'll leave that for another day.
1:04
However, the simplest way to reduce
coupling between two classes, is to have
1:07
the client class use an interface instead
of a concrete implementation of the class.
1:11
This gives us the greatest
flexibility when testing the unit.
1:16
We can provide an implementation of
a class that has already been unit tested,
1:20
or we can use a test double in its place.
1:25
Test doubles are also known as mocks,
stubs, spies, or fakes.
1:29
Actually these are all slightly
different concepts, but
1:34
as a group they're called test doubles.
1:37
You may hear people refer to them
all as mocks which is probably okay.
1:40
In this course I'll refer to
them generally as test doubles.
1:44
Test doubles are used to stand in for
1:48
parts of the program in
order to facilitate testing.
1:50
In order to have better control
over what is being tested and
1:54
to ensure that a unit is tested
independently from the rest of the code.
1:57
We can replace its dependencies with
much simpler objects that behave more
2:01
predictably.
2:06
To see what this really means,
let's code up an example.
2:07
Treehouse Defense has both towers and
invaders.
2:11
The towers try to disable
the invaders by shooting at them.
2:14
Here's a basic implementation of the tower
class notice that the tower class depends
2:18
on two other complex types
map location and I invader.
2:23
The question is how do we test the tower
class in such a way that if a test fails,
2:29
then we know that it's a failure
in the tower class and
2:34
not in one of these dependencies.
2:37
One way is to unit test
the dependencies first.
2:39
That's what we've done with
the map location class.
2:42
However, invaders are much more
complex objects than applications.
2:45
And we haven't written a concrete
implementation of an invader to test.
2:48
IInvader is an interface and
2:52
we don't know what the concrete
implementation of it will be yet.
2:54
However, when testing this class
we need to pass it in an array of
2:57
IInvader objects.
3:01
Since we don't have a tested invader to
pass it yet we can pass it a mock invader.
3:02
First let's create a test class for Tower.
3:07
I'll do this just by right clicking on
Tower and clicking on Create unit test.
3:10
I'll clean this up a little bit.
3:17
Now let's create a mock
invader in the test project.
3:21
I'll create this mock in its
own namespace and folder.
3:24
I'll call the folder Mocks,
so say add a folder.
3:27
Mocks, and in here I'll Add a new class,
3:34
and I'll call this new class
3:40
InvaderMock If we
3:44
had multiple invader mocks we'd probably
want to give it a more descriptive name.
3:51
We want invaderMock to implement
the I invader interface.
3:55
We can have Visual Studio do this code for
4:00
us just hit control dot on the keyboard
and select implement interface.
4:03
Now that we have a concrete
implementation of I invader to use,
4:08
let's go back to the tower test class and
start coding the test.
4:11
We can get rid of the constructor test
since it'll be tested in the course of
4:15
the other test.
4:19
And we'll remain this one to
FireOnInvadersDecreases Invaders help.
4:20
So in here we'll create
a new instance of a tower,
4:31
so I'll say var target = new tower.
4:36
And we need to give it
a location on the map, so
4:39
we'll say new Map location and
we'll just have this one be at 0, 0.
4:43
And we need to give it
an instance of the map.
4:48
So let's create that say var map,
4:51
= new map make it of size 3, 3.
4:55
And pass in the map.
5:02
Now let's create our array of invaders.
5:04
So we'll say var invaders
= new InvaderMock,
5:07
we need to add the namespace.
5:12
And it'll be an array of
a couple of invaders.
5:19
So I'll say new invaderMock and
it will need to have a location so
5:25
we'll just use a property setter for that.
5:29
So I'll say location =
new map location and
5:33
we'll just have it be at 0, 0.
5:38
And let's have a couple of these.
5:45
Now we need to call fire on
invaders on our target, so
5:48
let's say target.FireOnInvaders and
pas in the invaders.
5:52
And our assertion will be that
the health of each one of these
6:00
invaders has been decreased by one.
6:05
So to do that,
we can use the Assert.All method.
6:08
So we'll say Assert.All,
we'll pass in all of the invaders.
6:13
And then we give it a lambda.
6:18
So we can say, for each i in invader.
6:20
Assert that,
Assert.Equal that the health is one.
6:25
So we'll say i.health.
6:33
There we go.
6:37
Now, we need to think about what we
need our mock to look like, in order for
6:39
this test to work.
6:42
We can figure that out by looking at
both the test, and the tower class.
6:43
So, here we see that InvanderMock
is gonna need a public setter for
6:47
the location property.
6:52
And if we look at the tower class
in the fire on invaders method.
6:54
We'll see that it needs to have,
is active and
6:58
location and it needs to decrease
the health of the invader by this much.
7:03
And that's all it needs to do
in order to pass this test.
7:12
So we'll go over to our invader mock.
7:16
And just to keep this simple, we'll
just have HasScored always return false.
7:19
And our Health,
That's what's going to be decreased.
7:29
We'll have a getter and a private setter.
7:36
And we'll have it start
out with a health of 2.
7:43
Since after calling fire on invaders,
7:46
we're going to have
a health of 1 afterward.
7:49
That's what our test here is doing.
7:53
That's what it's checking.
7:55
After calling fire on invaders
the health should be 1.
7:57
So we need to start off with
a health of two in our mock.
8:01
And IsActive we can just have
that always return true.
8:06
IsNeutralize can always return false and
8:12
our location needs to have
both the getter and a setter.
8:17
So we'll say get, set.
8:23
So decrease health would
just be health -= factor.
8:29
Which this is the behavior we'd expect.
8:36
Now, notice that move still is thrown
knew not implemented exception.
8:40
The reason for this is in this mock we
don't have to do anything with move,
8:46
because move is never called by either
the test or the fire on invaders method.
8:50
So, we can just leave it as it is.
8:55
Now, if we go back to the tower test.
8:57
We'll see that we've got no red
squiggly so it should compile.
8:59
And let's compile and run this test.
9:02
Let's check out the Tower Test,
and it passes.
9:08
So this is just one example of
using a mock to facilitate testing.
9:14
The purpose of mocks is to provide a super
simplified version of a dependency
9:19
that has a very specific.
9:24
And very predictable behavior so that we
can test exactly what we want to test and
9:26
no more.
9:30
Let's take a look at that Mock again,
as you can see it's pretty simple.
9:31
A lot simpler than a implementation
of an invader would normally be.
9:36
Mock should be as simple as possible.
9:41
Otherwise we introduce the possibility
of a bug in the mock itself.
9:43
Notice that we didn't need to
implement every property and method.
9:48
Only what needed to be done
in order to run our test.
9:51
We could have many invader
mocks that are specific
9:54
to different types of test
that we want to create.
9:57
I mentioned earlier that mocks
are just one category of test doubles.
10:00
There are also spies stubs and fakes.
10:04
However many people refer to
all of these as mocks as well.
10:06
I've included some links in the teacher's
notes if you'd like to learn more about
10:10
these other categories of test doubles.
10:14
Just as there are frameworks for unit
testing, there are also frameworks for
10:15
creating doubles.
10:19
One such popular framework for
.NET is called MOQ spelled M-O-Q.
10:20
You'll find a link to more information
about the MOQ framework in the teacher's
10:25
notes as well.
10:28
As you can see we don't necessarily
need a special framework to create MOQs.
10:29
However they can help to
create better testing code.
10:34
Especially if a lot of different
test doubles need to be created.
10:37
For example using a mock framework we
could have written the entire fire on
10:40
invaders decreases invaders health test
without actually implementing this invader
10:44
mock class.
10:49
The behavior of the invader mock class
would have been put in the test itself.
10:50
Right here.
10:56
This would keep the mock
code close to the test that
10:58
was using it instead of
in a separate class.
11:01
While testing units in complete
isolation from each other is the ideal
11:04
it isn't always practical to do so.
11:08
For example we didn't create
a mock of the MapLocation class
11:11
in order to test the tower class.
11:15
In a lot of cases we can
get away with this and
11:17
still maintain a high degree
of confidence in our test.
11:20
The level of isolation testing to do
depends on the specific situation.
11:23
There are some situations where
isolation testing is unavoidable.
11:29
For example, in cases where there's
uncertainty in a dependency.
11:32
And example of this is a remote
service that isn't always running or
11:37
isn't completely stable.
11:40
You don't want to temporary failure in
an external dependency such as this
11:42
to cause your unit test to fail.
11:46
The dependency may not
respond in a timely manner.
11:49
This is another situation
when creating a test double
11:52
to stand in its place is a good idea.
11:55
Another time when test
doubles is unavoidable
11:58
is when the dependency isn't complete
enough to rely on during testing.
12:01
In this case, we can create
a simple version of the dependency,
12:05
just like we did with the invader mock.
12:09
This allows us to continue coding and
12:12
testing before all of
the dependencies are complete.
12:14
Test doubles are also used to provide
a reliable and predictable source of data.
12:18
A random number generator
that isn't random, or
12:23
a time source that can be set to any time.
12:26
Our examples where we could
use stand ins to remove
12:28
indeterminacy from a test environment.
12:31
You need to sign up for Treehouse in order to download course files.
Sign upYou need to sign up for Treehouse in order to set up Workspace
Sign up