This course will be retired on July 14, 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
Well done!
You have completed Unit Testing in C#!
You have completed Unit Testing in C#!
Preview
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