[No Audio]
In this video we're going to use
Mockito to test the LoginController.
So in the previous videos we
coded up this nice layered architecture.
Now we've got that done.
Let's create a test.
So let's suppose we wanted
to test this LoginController.
Okay, so we're going to test the LoginController.
So we're after testing this service method here.
So let's start by testing that.
So if we create a New Java Class, actually
we won't do that, just do shift command
T which we've seen before.
So if I go to LoginController, shift command.
T, Create a New Test.
[No Audio]
And we're just going to have this service method here.
[No Audio]
And let's put a setup method in as well.
[No Audio]
So now we're going to test this service method.
Let's just put , prefix it with test, testService.
So in order to test if we go
back to the test class with shift command
T, in order to test this LoginController we
need to number one create an instance of it.
And number two make sure that, that instance
also has an AuthenticationService as well.
So this AuthenticationService which is here, we're not
going to set the real AuthenticationService. Instead
we're going to set the mock AuthenticationService.
So therefore going back to our test,
[No Audio]
we want to have two fields,
[No Audio]
the controller itself
which is the system and the test.
That's the thing we're actually testing.
[No Audio]
And we also want to have the AuthenticationService.
I just call it service now.
And this is going to be a mock.
So we're going to set these up in the setup method.
So this.controller = new
logincontroller
[No Audio]
this.service= Mockito
[No Audio]
.mock
[No Audio]
AuthenticationService. That's great. That means
that every time we add a test method to this class by
using the @test annotation on the method, we're going
to get a new brand new LoginController and a brand new
mock to assign to the LoginController which we can
set up and code to act in the way we want.
So we're still going to do this assignment.
So let's do that now. So to do this let's go into
LoginController and let's add a constructor
which takes the AuthenticationService
So public LoginController AuthenticationService.
[No Audio]
Then we can do this. .authenticationService
= authenticationService.
[No Audio]
So now we should be able to
just create the mock before the controller.
[No Audio]
Now this is good. It means the LoginController
has been set up with a mock AuthenticationService.
Now you might be thinking, well, we could just
as easily take this here, delete that and just
pass it into the constructor and forget about this.
Well yeah, but if we did that, of course we
wouldn't then be able to access the mock to be
able to set it up to act that we wanted
to act inside each individual test method.
So that's why we need it in
a separate member reference, on the controller.
So let's put that back and then we're ready to go.
Just to prove this, if I set a breakpoint here and
then if I go to Debug testService, I expect that
I've got that test fixture set up correctly. Before
that quickly I'll just set it to JDK7. Come to here.
Preferences
[No Audio]
Java Compiler Target bytecode version and just
change this to 7, then rerun with controler.
Sorry, redebug with controld, then
we hit the Breakpoint. So if we're looking now, this is
the instance of our LoginController test. And inside
here we expect to see the LoginController itself
plus the service, which is set on that controller.
Just double check that we've
got the login controller here.
You can see we've got the service also, which
is a mock, and inside the controller we expect
that mock is assigned, and you can see here
it's assigned to the AuthenticationService.
That's good. So let's stop that,
get rid of that.
So remember, we have arrange, act and assert.
So now arrange, this is where we have an opportunity
to set up our mock, to set it up as we want it to act.
So for example, I can do this.service,
[No Audio]
I can do Mockito.when
[No Audio]
this is a static method on Mockito,
which enables us to plug in behavior to this mock.
Say if we just do an on demand static import for that,
that should be the whole Mockito library, which we
want. So if we just do Mockito.*, then we should
have access to all of these methods here basically.
And the ones we're really after, are the mock method.
So we can take that away because it's a static import
now, the when method and the then method.
So how when and then works is basically we
say when and then we pass in the mock
and then invoke the actual method on the object
and we're just going to say any string.
[No Audio]
So whenever any string is passed for
the username and any string is passed
for the password, regardless of what's passed.
Because now this isn't a data test, we're not testing
a function as we've seen before, what we're testing now
is actual behavior, which is a difference,
[No Audio]
say .thenReturn
[No Audio]
and it wants us to return something of type boolean.
So we say .theReturn true.
So what we're doing here basically is we're
setting up the mock to act as if
the authenticate method always returns true.
So let's go back to the authentication method, in
AuthenticationService, this method here usually
delegates to the user repository, finds the user by
the username, gets a user object, then looks the
password on the object and see if it equals the
password. That's what it usually does.
However, what we're doing with the mock
is we're basically effectively commenting all that
out and replacing with the custom implementation.
And the custom implementation
effectively is returned true.
I'll do that now.
That was just for illustration purposes, but
yeah, you get what I mean.
[No Audio]
So to go back to the LoginController test, we're
saying whenever we call authenticate with any string
for username, any string for password, then it's
going to return true, and this sets us up in a happy
path scenario. We're really testing the happy path here
where the user is going to be logged in.
Okay, so what happens when the user is going to
be logged in, from a production code point of view?
Well, let's look back at the LoginController
and look at the logic there.
If this method here, if AuthenticationService.authenticate
passing in the username password.
If it does equal true alright, then we're going
to return the path to the home page.
And if it's not true, we return
the path to the login page,
but we're working with the fact that it
is true now because that's how we've set
up our mock for this specific test.
So when it is true, we expect that the
user will be effectively sent to the home page.
Okay, so how do we communicate like the test?
Jump back to the test, shift command
T again log and control the test.
We basically do the action.
So this is where we're going to call the controller.
We can prefix it with this dot
also, but we don't necessarily have to.
In fact, I prefer not to.
So we'll also take it out from here as well.
[No Audio]
The action now is controller.service and
we can pass in any old thing now it doesn't really
matter, tom password123.
But the key point here, of course is that
we get back the view name or viewPath.
Let's call it viewPath.
So in this case when we get the viewPath
back we expect now that it's equal to /home
so we can do the Assert.
[No Audio]
assertNotNull(viewPath).
We don't want to get back a null viewPath.
That will be wrong.
Next, Assert.
[No Audio]
assertEquals expect and actual.
So we expected /home and the actual is viewPath.
So now if we run this
[No Audio]
we can see that that test has passed and we probably
want to give it a more descriptive test name as well.
For example, testService_validUsername
[No Audio]
and password
[No Audio]
logs in user, for example. That's nice.
It means we've basically got a test
method now which is named descriptively to
describe what the test is actually testing.
So that's nice. We've now seen first hand how we can
use Mockito to test the LoginController.
Let's jump in now and we'll do another one and we'll
explore how to test the AuthenticationService .