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
Video Player
00:00
00:00
00:00
- 2x 2x
- 1.75x 1.75x
- 1.5x 1.5x
- 1.25x 1.25x
- 1.1x 1.1x
- 1x 1x
- 0.75x 0.75x
- 0.5x 0.5x
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