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
It's super important to also know what you shouldn't test, and what you should stub out. Let's explore!
Coverage
Mocking Libraries
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
There are things that
we shouldn't test and
0:00
if we follow the best practices
that we've picked up thus far
0:02
we'll probably not end up falling
into some common pitfalls.
0:06
You wanna make sure that you don't
test stuff that can't really break.
0:10
A good example of this is
testing of getters and setters.
0:13
In a behavior to find test you probably
won't even think of this, but for
0:18
those test that's simply
test all the methods,
0:21
you might actually encounter someone
testing a method like test get name.
0:24
That's pretty silly right?
0:28
I mean, how could that actually break?
0:30
Especially if it's just exposing
a private member variable.
0:32
A great quote found in the JUnit
frequently ask questions is this.
0:36
Test until fear turns to boredom.
0:40
Don't feel like you need
to test 100% of your code.
0:42
Especially the bits that can't break.
0:45
There are actually tools that fall
into the category of test coverage.
0:48
Now they will report on parts of
the code that didn't get executed
0:51
during your test run.
0:55
Thus proving that they aren't
actually proven to work.
0:56
Usually in these tools, you'll find that
your code is actually exercised anyway.
0:59
Check the teachers notes for
more coverage on coverage.
1:04
So what happens when you want to
test code that relies on other code?
1:08
Now if you don't do
anything about it at all
1:13
in the best possible situation assuming
the other code is tested as well.
1:15
You end up testing the same code
twice during your test run.
1:20
Now let's start imaging
some worse situations.
1:23
What happens if something
other than that code breaks?
1:27
Does that mean the code you were
testing specifically is broken?
1:30
It doesn't mean that, right?
1:33
The problem is actually somewhere else and
1:35
it really should be
the responsibility of another test.
1:36
Our code should be isolated
to ensure that we are testing
1:40
only the behavior that we are expecting.
1:43
When a test fails for outside reasons,
trusts in the test begin to dwindle.
1:46
If tests aren't trusted,
errors will be ignored.
1:51
You want trust in your tests,
it's why wrote them after all!
1:55
So an even worse situation,
1:59
what if that other code takes
a really long time to run and set up?
2:01
That means we're paying for
the timing hit when we don't need to.
2:06
If tests don't run fast,
they don't get run.
2:09
It's a sad fact, you can put
a lot of work into your test, but
2:13
if they don't get run because it takes
too long it's simply just wasted work.
2:16
So how do you work around this, how do
you make sure that you are only testing
2:21
the behavior that you intend to and
you isolate it from everything else?
2:24
Well the answer is test doubles.
2:28
Test doubles can be though of like
a stunt double for your test.
2:31
They are used to replace actual
code with code that looks and
2:34
behaves pretty similar to the original.
2:38
Sometimes there are different levels
of testing that are required to
2:40
fake things out.
2:43
Let's talk through the different types and
2:44
then we'll look at a few that
we be able to employ in our app.
2:46
The first two test double
patterns are usually hand rolled.
2:50
Fake objects actually have
working implementations but
2:53
take shortcuts to make
things a little faster.
2:57
Now this can be a reimplementation of
a database so that it all runs in memory.
3:00
And Stubs match the needed api for
the test but
3:04
usually just respond with a canned answer
and only work in a specific use case.
3:07
This is handy for heavy calculations or
places that might network connectivity.
3:13
Instead of performing anything they
just immediately return the same
3:18
answer every time.
3:21
Now, these next two are usually
provided by a third party library.
3:23
Spies are basically fancier stubs that
also record some information based on how
3:27
they were used.
3:32
You can verify that things happened, and
that they happened in a certain order.
3:33
Mocks are designed with expectations that
3:38
form a specification of the calls
they are expected to receive.
3:41
They can throw an exception if they're
used in a way that wasn't expected and
3:45
are also checked during verification
to insure that they got
3:49
all the calls they were expected.
3:52
We've been focusing on the components but
we haven't yet
3:54
taken a look at the vending
machine itself.
3:57
One of the things that happens on
a proper vend is that a notification
4:00
is sent to text on every
successful item sale.
4:03
Let's make sure that we put
a test double in place so
4:07
that every time something is vended in our
test ed don't send a notification to them.
4:09
He wouldn't like that.
4:13
So if we open up our vending
machine class and we take a look
4:15
here in the constructor we'll notice
that notifier is the first parameter.
4:20
So let's go ahead and
look at the notifier definition.
4:25
Oh, sweet it's an interface, so
any implementation of notifier
4:29
as long as it implements
the methods defined here right?
4:33
Which is just on sale it'll work.
4:36
Now I wrote things this way
specifically for this purpose but
4:38
it is indeed a best practice.
4:43
But, this is a form of what is known
as dependency injection, or DI.
4:45
This is called constructor dependency
injection, and it allows you to easily
4:50
switch out implementations as needed,
and it's super-handy for test doubles.
4:54
We'll talk about this a lot more
in upcoming courses but for
4:59
now, just know that this class is setup
specifically to allow us to push in
5:01
exactly how we want our notifier to work.
5:06
So, actually this pattern would
normally also, right this constructor
5:08
would normally also take a chooser and
a creditor and the constructor right?
5:14
So, you can build this machine however
you want which is kinda how it works in
5:17
real life, right?
5:20
I mean remember, there's all
sorts of different machine types.
5:21
Ones where you can pay with your phone and
5:23
ones where you can choose with a large
button, but you could push those in there.
5:25
A dependency injection is one way to
tackle this concept of configuration.
5:28
Okay, enough talking.
5:33
So let's rock out a test picture for
this vending machine.
5:34
So I'm gonna do, Cmd+Shift+T and
create a new test.
5:38
Vending machine test.
5:41
Let's go ahead and set it up, okay.
5:42
All right, so we'll go ahead and
make a field for the vending machine.
5:45
And just to recall from before,
let's go ahead and make an inline class.
5:54
Okay, so remember you can put
a class inside of a class.
6:02
So let's do that.
6:04
We're not gonna use it
anywhere else outside of here.
6:08
And we're gonna make sure that
it implements the Notifier.
6:10
And it's saying that it doesn't implement,
so let's just go ahead and I'm gonna say
6:15
Implement methods because that will say
everything inside of this requires this.
6:18
So we'll go ahead and say on sale,
and on sale returns a void.
6:22
So we don't actually need to do anything.
6:28
We don't want it do anything, right?
6:30
So let's just say, return.
6:32
Okay, and now in our setup,
6:33
in our before method here let's
go ahead and make a new Notifier.
6:35
And see how I'm able to access the class
above, right, it knows about it.
6:43
So we'll create a new machine.
6:49
It's going to take the notifier
that we just created and
6:53
we'll just put ten, ten, ten in there.
6:56
Right?
For rows, columns and back.
7:00
So and let's go ahead and
let's restock it as well.
7:02
This will be part of the arrangement.
7:05
In A1 we want some Twinkies.
7:07
I really should have went for
product placement on this, right?
7:10
Okay and let's test our happy path right.
7:16
Let's go ahead and let's get some
of those delicious Twinkies.
7:19
So we'll go ahead and say,
7:22
Make a new test called
vendingWhenStockedReturnsItem.
7:28
And let's add some money,
7:37
a little bit more arranging here,
put 75 cents in there.
7:41
And then let's get the item out.
7:46
And then let's make sure that we
get our delicious Twinkies up.
8:00
Okay, let's go ahead and run that.
8:13
And if we look back at the vending machine
we'll see that when we called vend,
8:19
it did call notifier onSale item.
8:23
And all we did was just return.
8:25
Our implementation, right immediately
when it called that it returned,
8:27
instead of connect into the internet in
sending a message, it just simply return.
8:30
So we stabbed out the method so
8:35
it won't take forever as well,
as it won't notify for
8:38
text that someone bought Twinkies every
single time this test was run, right?
8:41
Pretty cool, isn't it?
8:45
Oh, and while we're here, let's look at
that method refund money, can that break?
8:46
No, not really.
8:53
And it should already be tested
in the Creditor test, right?
8:54
So we don't need to test it here.
8:58
Test until fear turn to boredom.
8:59
I'm not afraid of method.
9:02
Testing that would definitely be boring.
9:03
If we wanted to,
we could ensure that when vend was called
9:07
that the appropriate
notification was sent.
9:10
We do that by creating a mock.
9:13
You could definitely create your own mock,
right?
9:16
All we'd need to do is add some private
fields to our stub class and then set
9:18
those fields and access them later to
make sure that the method was called.
9:21
Tread lightly here, the more you do this,
the harder it gets.
9:25
Because of this difficulty there
are awesome Mocking Libraries available.
9:29
If this is something you're interested
in learning more about please check
9:33
the teachers notes.
9:36
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