So it's time to test our handlers and testing handlers can always be a little tricky, but it's not
that bad and we'll go through the entire process.
So I'm looking at my handlers right now.
And when you look at these, you will realize pretty quickly that we need a fair bit of information
before we can ever test a given handler.
For example, I'm looking at the home handler.
I'm going to need a response writer.
I'm going to need a request.
I'm going to have to have access to the session because I'm putting something in here and, you know,
I'm sure they're not going to be using that later.
I'll take that out of the home handler at some point, but I'm definitely using it in other places.
So, for example, when I do a post request, I store the reservation in the session.
So there's a fair bit of things that I need to actually have set up.
And what I'm going to do, of course, is create two files.
One of them is where I'm going to set things up.
So when the handlers folder, I'll create a set up, underscore Testori, go or create that.
That's where we're going to set up our testing environment.
And then I need a place for the actual test themselves, which of course needs to be called handlers.
Underscore Test Dutko.
And again, just to remind you, if it doesn't end in underscore test go, it's not considered a test.
So I've created both of those files.
And let's start with the setup and let's think about what we need to have in here.
Well, it's pretty much the same sort of thing that we have in our main function.
So on Mango, I have this run function and I definitely want most of this stuff.
So I'm going to copy all of this.
I shall copy all of it right down to here.
And I'll go to setup test and I'll create a function.
Now, I could use the test main function that we talked about last time, and we'll do that in the next
step when we get to testing or render functions.
But for right now, I'll just demonstrate that you can use any function you want to.
So I'll create a function, I'll call it.
What shall I call it?
I'll call it func.
Get roots, because I know I'm going to have to have roots at some point, otherwise I can't call the
handlers at all.
And since it's, you know, going to be giving us roots, it'll hand back exactly what our roots application
does.
So if I look at Ritsuko go, it returns and it should be handled.
So I'm going to need that.
So I know I'm going to be returning an HSDPA handler at some point.
And a better spell funk.
Right.
All right.
And then I'll just paste in what I got from my main function.
Now, we have some errors here right away.
I don't have an app variable.
I don't have a session variable.
So we can create those.
That's no problem.
Let's create our app variable, which will be var app config, app config that will hold our application
configuration and let's create a special variable too and we'll call that session.
And that's a pointer to export session manager because we're using our Alex Edwards ESCs package and
that's what this session variable is for that given package.
So great that that fixed up most of the errors.
But we still have one here.
Log fatele cannot create template cache.
Well, we're going to have to change that template cache in a minute, but we just won't return it here.
And down here we have Handler's New Republic.
We're in the handler's package.
So I don't need to actually specify that the same thing here for new handlers.
OK, and then we have render new templates in app and then we actually need our roots.
So let's open up our Ritvo and we'll copy all of this right down to here.
Copy that.
Go back to our setup test and we'll pasted in.
And again, we have some errors.
Now the errors are once again because we're actually in the handler's package.
So I don't have to specify.
I don't have to specify the final package.
So what I can just do is edit, find, search and replace.
And I will look for handlers thought repo and just change it to repo replace old and that fixes those
errors.
Now we also need our middleware.
Now our middleware is stored in the main package.
That means we can't import because you can't import your main package.
But what we can do is open the middleware file and just copy those
and close this and come back here and we'll just paste.
I'll put them down here.
It doesn't matter where they are, but I'll paste them in here and suddenly all of our errors go away.
So this probably set up our environment.
Let's just check everything and make sure we've got it right.
So we come in here and we say, get roots, we register the reservation, we're going to store the section.
We have to have that because one of our handlers does precisely that.
We set in production defaults.
That's fine.
We set up our session exactly as we do in our our main function.
Then we store a session in the application.
That's good.
Next, we have render create template cache.
So let's look at the create template cache function that's in the render package.
So this looks like it should work, but it won't.
And the reason why it won't work is not immediately obvious.
And it's right here when I load the templates like the page templates, for example, I'm hard coding
the path to the templates folder and that's fine when we start our application from the root level of
our directory, as we've been doing all along.
But when we run our tests, our handlers underscore test.
When we write those tests and run it, we're not actually running the application from the root level
of our folder.
We're running it from instead the handler's folder, which is inside the internal folder, which is
inside the root level of our application.
So we need to change that.
And it's really easy to do what I'm going to do.
It's go to the top of this file and create a new variable, which I will call path to templates, and
I will initialize that with the default value of doggy templates.
Then I'll go back down to my create template cache and I'll just make this a format as print F and get
rid of the DOT templates, put in a string placeholder and then put in our path the templates.
Now when this application runs, I can actually set that variable.
Now this isn't going to be terribly useful right now, but it will be useful when we get to the render
parts.
We may as well do it right now.
I can actually substitute whatever I need at the first part of this path to the templates using this
variable.
So do the same thing here.
This will be a placeholder for S and then format as print F and put in our variable path the templates
and the same thing here.
This will be A.
S and we'll put in format as print f path to templates and closer parentheses.
All right.
So that.
We solve that problem, so that's something that's going to be helpful in the next section when we start
testing our vendor handlers, so we may as well do it right now because that hard coating is going to
be a bit of an issue.
But in our setup tests, I actually don't want to call this template cash directly.
What I'm going to do instead is copy that function, the entire thing, just so I have complete control
over my testing environment.
And there are many ways to do this.
But this one works and it's pretty straightforward.
And I'll put another function in here, a pastebin.
But instead of calling it create template Carse, I'm going to call it create a test template cache.
And as usual, the idee can't find its template.
So I have to import that and we need to create a path to templates variable.
So we'll do that up here.
First of all, let's tell Goaland that we're using the HTML template and that'll solve that import problem.
Good.
So those are gone now.
Yeah.
All I have to do is create that path, the templates.
So her path to templates is going to be equal to DOT and then up one level, which gets us to the internal
folder, then up another level, which gets us to the root level of our application, which is where
we want to be, and then the templates folder.
All right.
So we have one more error here functions.
So let's go back to our render package right here and find out what functions is.
And this is a variable that holds all of the functions that we want to put into our make available to
our our goaland templates.
So let's go back to set up test and just create that variable and we can leave it empty and it should
solve our problems.
Good.
So there it looks like we've got things set up.
Let's make sure when I call the get root functions, it registers the models reservation into the sessions.
So we know that we can use that in the session.
We set our in production default, which is fine.
We create our session, which is great.
Then we store a session in the variable, then we create our template cache right here and we say app
template cache equals T.C. And then we have app use cash equal to false.
And that could be a bit of a problem.
Let's think about that for a minute.
Why wouldn't that be a problem if we don't if we have used cash that defaults, it's going to rebuild
the page on every request.
But when it actually rebuilds the page in render, let's see this.
If app use cash is to true, then get it from the template cache.
Otherwise create template cache.
And that's a problem.
That's a problem because when it calls this function, it's going to be using this as the past of the
templates.
So let's go back to our setup test and make app use cash equal to true.
And that should work for us.
OK, so we've got this set up and let's write just one test just to get things out of the way and see
if we can make this work.
And what I'm going to do is think about how I'm going to do this.
Well, first of all, I have a whole bunch of pages I want to test or a whole bunch of handlers I want
to test.
I can write each test individually, but it seems to me it makes a lot more sense to run table tests.
And when I call a given handler, I need to know certain things.
First of all, what's the path to it which matches the things in our resolve and our routes file in
this case are in the the set up underscore test.
So I need to know that for some of the routes I'm going to be posting information.
For example, when I post to make Dasch reservation, I'm filling out a form and it has first name,
last name, phone, email, and eventually it'll have more information.
So I'm going to need some method of of holding post data.
All right.
So let's think about what we're going to do here.
What I'm going to do, first of all, is create a type.
And this type is going to be something that holds whatever we're posting to a page.
So I'll call it post data and it's just going to be a struct.
And inside of that, I'm going to have two things, just like we have in our forms.
For example, on the input for first name, we have an input with the name of first name and the value
of whatever the person typed into that form.
So I'll call the first part key, which I will spell with an E and on an array, which is a string,
and then whatever they type into it will be a value, which is also a string.
OK, so I've created that.
Now I'm going to create a variable for the actual tests.
We'll create a bar and I'll call it the tests.
It will be a slice of struct because we're going to have more than one or potentially more than one
test we want to run in our table test instructs is not plural.
Inside of that, I have to define the actual struct.
So what are we going to have?
Well, first of all, I'm going to call name.
That'll just be the name for the test and it'll be whatever I want to call an individual test.
Then we have to have the URL, the path which is matched by our roots.
And that's a string then I need.
To have the method, is it a get or a post that's just a string, then I need to have possibly Prem's
those would be the things that are being posted and that's going to be, you know, a form can have
more than one input.
Most do.
So it has to be a slice of post data, which we just defined right up above here.
And then finally, we need something to test, something to say whether or not a test has passed.
And the easiest thing to test for right now, at least, is what kind of response code are we getting
back from the Web server if it's 200, everything worked the way it's supposed to.
If it's 404, page is not found.
If it's in the 300 range, it's a redirect.
So I'm just going to say expected status code and that will be an end.
OK, so we've defined our structure, but it doesn't have any values.
So I'm going to put an equal sign here.
Just make the shorthand.
I'm going to define my struct and populate with data all in one step.
So because this is a slice of structure inside of these parentheses that I just created, I'm going
to have each entry in its own curly braces.
And the first thing I want for my first one, let's just test the homepage will take Will Naimark test
home because we're testing the homepage, the path that is just slash and that's straight out of our
routes file.
The method is get because there's no form being posted on the homepage and then I need to specify the
parameters.
Well, there are no primes for the home page, so I'll just put in a slice of post data and make it
empty.
And that satisfies that requirement.
And for the status that I'm getting back from the server, I could put 200 because that is status.
OK, but I like to use the constants built into the standard library http status.
OK, all right.
So there is one thing we can test now.
Let's just test that one by itself to make sure we have everything right.
So we'll write the actual test here.
Func test handlers, which is just a name that I'm choosing because I'm testing all of my handlers and
has a parameter of T type of pointer to testing Dorte.
And inside we first of all, to get our roots.
Well, remember, we have this function we set up in our setup underscore test called Get Roots, and
that returns.
First of all, it sets a whole bunch of things up and then it returns mux and mux is our router.
So we can just call that function.
So go back to handlers test and say route's is assigned the value of get roots there.
Now we have our roots.
Now, here's the cool part.
How are we going to create a Web server that actually returns status code, something we can post to?
We need to, in effect, create a server.
And we also need to create a client that can call that server.
And the great thing about testing ingoing is that all of this is done for us.
We can just create a test server and stored in a variable.
So I'll create a variable called for test server and I will assign that the value of HTP test DOT New
Teela server.
And that requires well, you see what it requires just by rolling over top of it.
It says it requires an HIV handler, which we just got when we called get route's.
We put our reach in there.
Now, I've created that server.
Now, once you create the server, it's going to fire up for the life of this task.
It's going to listen on a poor it's going to open some things.
And it's always good practice to close that when you're done with it.
So we can do that using our defer keyword defer close, which is a function built right into that package.
So as you know, from way back when Defer doesn't get whatever is after the keyword deferred doesn't
get executed until after the current function is finished.
So when test handlers is finished, it will close the test server.
Now we need to do something to actually run our individual tests.
And this is a table test.
So we use exactly the same logic we did last time around, the last time we did a table test.
And it's been a while, but for I don't care what the index is, so I'll use the placeholder for that,
the blank underscore and then I'll name my individual test as I'm running it e because I got to call
it something and it works.
That's going to be assigned the value of range through the tests.
Now inside of that for loop, there are really two kinds of tests we're going to be running.
There are ones that may get requests like just showing the homepage or showing the about page.
And there are ones that make post requests, ones that are where a user fills out a form and submits
that as a post.
So we need to determine which time we're going to run and we can do that really easily.
If IDOT method, which we specified right up here, if that's equal to get do this, otherwise it's
post.
And right now I'm just going to do with the.
The deal with the debt requests, we'll do the post requests in the next election.
So what do we want to test here?
Well, we actually need to make a request as a client as though we were a Web browser accessing a Web
page.
Unfortunately, that functionality is built right into our test server.
We can call TEUs client, which an up close client, which effectively creates a Web browser or a Web
client.
And then we'll call the get method on that and we'll call our You URL.
Now, you might think that's just Iida neutral, which is in this case a slash, but actually we need
a little bit before that.
We need the part that actually calls the Web server and we don't know what that is.
We don't know what port it's listening on.
Fortunately, TSA does our test server has your URL as an available value.
We can call and all we do is append our URL to whatever the test servers you are.
So we've now called that now.
We're not doing anything with this.
We need to store that in a response, which I'll call response and get actually returns.
As you can see, if you roll over it.
Two things.
It returns the response, which is a pointer to a response, and it also might return an error if something
goes wrong.
So we have to track for that slow response and error are equal to our test server client.
Make a get request to the URL we want to test, then we check for an error.
So if the error is not equal to nil, then we what are we going to do?
Well, let's go with T to log the log there and then we'll fail the test.
Edenvale teed up.
Fadal will kill it for us and we'll put the error in there too.
All right.
If we get past that, then we need to check our response.
And how are we going to do that when we're going to do it?
By looking at the status code, we get back from our test server and comparing that with our expected
status code.
And all we have to do is say give respect.
Status code is not equal to our expected status code e dot expected status code, then write an error
teig error and they still use error f g so I can put a more meaningful error in there.
It works just like s print F and I'll just say four and the test sname, which is a string expected
the integer what our expected value is but got the other integer, the one that we actually got back
then we replaced those placeholders with our actual values.
So Eatock name is the name of the test idot expected status code is the expected status code and respect
status code is the status.
Could we actually go and that should be enough to test our homepage.
So let's try it out, go to my terminal and let's run the tests, make sure we're in the right direction.
I'm not so CWD internal handlers now I'm in the correct directory and let's run the test.
Go test dash verbose.
And it failed.
What did it fail with?
Oh, I see what I forgot to do.
So let's go back.
I forgot to actually use that test to create templates in our setup.
So we're going to set up Dutko, set up underscore Testico and find the part where we actually yes.
This should not be render create template, template cache.
And I said we built a new one and put it in here just for this purpose.
So let's go back to our terminal, clear the screen, go test, Dashti.
And it passed perfect.
All right, so let's go back and try a few more routes.
So in our tests, we need to add some more test data.
So let's see what else we have for gets under our setup test.
Let's look at our routes.
We have aget for about four generals quarters and four major suite.
Let's do those.
So we'll just duplicate this one twice, three times.
So we have one for about one for generals quarters one four major suite.
And all I have to do here is change the URLs, slash about generals quarters and Meijers suite.
Let's see what other ones we have.
We have a get for search availability.
So let's do that one search availability, which I'll just call SRN and change the route to search availability
anymore.
We have one for contact and one for make reservation.
So contact and make reservation contact, which is just contact and make reservation, make a reservation.
All right.
So we have those set up.
All look right to me.
Let's find out is there and we will go test Rushdi.
And they all passed good.
Now let's make sure it's actually working instead of having status.
OK, here, let's change that to status not found.
Now, this should fail because you won't get a 404 when you go to make that reservation.
And it felt good, so we'll just change that back to status, OK, perfect.
So those are our get requests and in the next lecture we'll actually do our post requests.
And that's not terribly difficult either.