OK, one more thing I want to turn our attention to, and it is a very important component and one that
gets ignored far too often by developers, especially new developers, and that is testing when we write
code, we want to write tests to ensure that our code actually does what it's supposed to do.
Fortunately, go makes this remarkably easy.
So, first of all, we need something to test.
So what I'm going to do, I have a new project here with one file named Echo, and inside of that I
have an empty main function.
And as you have to have, I'm going to create a new function.
I'm going to call this function divide and it's going to take two parameters, X and Y, not very original
variable names, but they'll do the trick and they're going to be off type float 32 and it's going to
return one of two things.
Well, Ash is going to return to things.
It's going to return a float 32, which will be the result of our division and an error which will have
an error if there is an error or it will be nil if there is no error.
So it takes two parameters and it returns to things.
Now, the very first thing we need, of course, is a place to store a result.
So I'll find a new variable var and I'll just call a result and it's a type float 32 and then we can
do our division.
Our division is result equals X divided by Y and then I need to return our result and an error if we
have one.
Now sadly this will never throw an error that I can catch, so I need to check for something.
Now what situations are there.
We're dividing one float by another or one number by another will result in an error.
And if you took math at all at any point in the past, you'll know that division by zero is generally
frowned upon.
You can't divide something by zero or you get an undefined result.
So that's our error.
So I can just check to say if y which is what I'm dividing by right here, if that's equal to zero,
then return an error.
So I will return and I'll return.
I have to return to things.
I'll return result which is set to zero right now because I've just initialize that, not done anything
with it and then I'll just generate my own error.
And it's as simple as this errors knew and then I will put in my error.
Message cannot divide by zero.
That's it.
So now I can return nil down here because there is no air.
So let's go through this.
Here's a function called divide.
I initialize a variable type happens to be float 32.
I checked to make sure what I'm dividing by our deviser y is not zero.
If it is equal to zero, return the result, which is zero because I haven't done anything with it and
an error that I've created myself.
Otherwise, if Y is not equal to zero to the division, return the result and return nil for an error
and appear in the main function.
All I have to do is call it so I'll say result and error, which is an error there.
Assign the value of divide and I'll just do one hundred divided by ten and they'll check for my error.
If error is not equal to nil, what should I do.
I should just say, well, log print line error and return.
Don't do anything else.
Stop at that point.
Otherwise, what am I going to do.
Log print line result of division is and then my result.
All right.
So I can run this program.
Go run.
May not go and it should work.
Result of division is 10.
Perfect.
OK, now what if I try to divide by zero, just changes to zero, clear the screen.
And run it again cannot divide by zero.
That works great, but the entire purpose of this exercise is not to learn how to divide because you
probably already know how to do that.
It's to write tests.
So here's how you write tests and go in go the tests.
The tests themselves live right beside the coalition trying to test.
So I have one file, mango.
I'll now create another file and it has to have a specific kind of name and fortunately is pretty easy.
So when I create my file, I will call it new go file, main underscore test or go, which means these
are the tests for mango.
So it has to end with underscore test go.
So how do we write tests?
Well, I'm going to show you two ways, one way, which is kind of manual and slow and one another way
which is way more efficient.
But we'll do the easy ones first, the manual ones to write, to write a test and go.
It's just a function.
And you have to give the function a name and it has to start with the word test.
Otherwise it's going to get ignored.
And I'm going to test divide because I have a function called write.
So I'm going to do that.
And it takes this for argument's T is the conventional name that you're going to use for this variable.
And it's a pointer to testing Dorte, which is a built in package.
So you see that an important testing for me.
Now, I write my tests and all I do is I need to get the result in this case.
I don't care what the result is, I'm going to call that function.
I'm going to check for an error and I'll divide, oh, let's say ten point zero and one point zero.
OK, if error is not equal to nil, then what do I do?
I throw an error, but I don't throw a standard error.
I throw a testing error.
T dot error.
Got an error when we should not have.
So I'm checking for air, but I'm not checking for errors in my programming code.
I'm checking to see whether an error is actually thrown.
So in this case, when I divide ten by one, that's absolutely valid and I should not get an error.
So all I'm running here is a test to say if I divide ten by one, I should not get an error.
If I do, then fail this test.
So let's run this.
And here's how you run tests and go go test.
That's pretty easy and pass.
OK, and I can actually do a little bit more detail.
Go test Dash V for verbose and it says I'm running testified, I pass testified and it told me how long
it took to run all the questions around all the tests.
Now that's one test.
Let's try copying this and I'm going to copy and paste it and give it a new name test, bad divide,
I'll call it this time, meaning I'm testing for bad division.
And this time I'm going to say divide ten by zero.
In this case, what should happen if error is equal to nil?
If it doesn't throw an error we say did not get an error when we should have and again, think it through.
If I divide ten by zero, it should generate that error that we wrote in our function and return zero
and an error.
So error should not be equal to nil.
If error is equal to nil, then I failed the test so we can now run the test again, go test and again
it should pass and they both pass.
Now, the problem here, of course, is what if I really want to test my division function thoroughly?
I'm going to wind up writing one function for every one of these tests, and that's really, really
inefficient.
So instead, let's run what's called a table test and we'll do this, first of all, by showing what
kind of data I want to test.
So right at the top of my program, right after my input statement, I'm going to write a variable tests
and it's going to be equal to a slice of stroke's slice of strokes.
And inside of that, I have to define the struct.
So first of all, I want to give my testimony, which is just a string.
Then I'm going to give my name, my dividend, my first number that I'm passing, which is a thirty
two dividend.
I better still write and then the deviser, but I'm dividing by which is again a float thirty two.
Is that enough.
No it's not.
I want to also include what do I expect to get from the results of this division.
So I'll call it expected and it's a float.
Thirty two and finally I'm going to put in one more variable.
Is an error expected.
So is error which is a boolean true or false.
OK then that defines my struct.
Now it's populated with some test data and what we're going to have is every entry in this slice will
be a test that I run once.
So first of all, I'm going to call my test is valid data and that name can be whatever you want.
But my test is testing with valid data.
I'll pass in one hundred point zero as my first number, ten point zero is my second number and ten
point zero is the expected result.
And this should not throw an error.
So each of these values corresponds to each of these in order.
So I'm having a test named for all the data I want to divide.
One hundred by ten.
I expect to get ten as a result and I expect no error.
Now let's duplicate that line and call it invalid data hundred divided by zero and I can put zero point
zero because it's a float and the result I'm expecting is zero.
And am I expecting an error?
Yes, if I try to divide by zero, then I should get an error.
OK, let's just go with those two for now.
These two effectively duplicate the two tests I've written already.
I'll leave those there.
But now I want to write a new function func.
I'll call it test division and there's no tie and function test division.
And it is again a Ts type testing T.
And I put its parentheses there as curly brackets.
Now I'm going to range over my test variable so we can know how to do that.
We've already done that for I ignore the first one.
I don't care what the index is for each test and I'll call it teet, which is pretty common when you're
changing over tests equals range tests.
And what do I want to do inside of that test?
Well, first of all, let's just call that function.
Got what am I getting from the function error?
If there's an error, populate that variable, otherwise leave it is nil and call the function divide.
And I'm going to call it the passing the two arguments right from this slice.
So I address those by going to dot dividend t t dot divisor and then I actually run my checks.
So first of all, what am I checking for.
Well let's check, first of all to see if it should have an error.
If T t is error.
In other words, if this test is supposed to throw an error, then check to see if the error is now
because of the error is no, I failed the test.
If error is equal to nil, then fail the tests.
I can put T to error expected and error, but did not get one.
So that's the first check.
So a second case would be if the error is not equal, if there is equal to.
So that would be an opt out.
And now I can check to see if error is not equal to nil, then I throw another Teda error.
And this one is did not expect an error, but got one.
And then to confront the threat, which is er error, I could just put air there, but you can also
call the method on that which will give it as a strength.
OK, so that's our first case.
And then finally, we need to check to see did we get what we expected to get.
If God is not equal to TTD expected, then throw another Teege error.
And this time I'll use Şeref because I'm going to put some placeholders in there.
Expected percent F, but got percent F.
And then I just populate those placeholders with expected and got so I expected to the expected and
got there.
All right, let's run this test and see what happens.
Go test.
And they all passed, and if I do go test you go test Daschle, you see, that is actually running those
test runs test division twice because I have two values up here and then it runs the two manual ones.
But I don't really need those anymore so I can get rid of them because I'm already testing them.
And the great thing about this is if I want to run more tests on that, I just duplicate this and put
some more values in here.
So I'll put one where I expect certain results expected or expect five.
How do I get five?
Well, fifty divided by ten should give me five and now I can run those tests.
And it works great.
OK, let's take it here, expected an error, but did not get one fail test division, so.
Oh yeah, down here I expect no air false.
See, that's how they work.
So clear the screen, run this again and away it goes, if I want to put another one in there, say
expect fractioned so we're not going to do a whole division this time.
So we'll do minus one divided by minus 777.
And what does that give us?
Well, I already did this on a calculator.
It gives a zero point zero zero one two eight seven zero zero one three.
And if I typed that right, this test should pass.
And it passed, and that's all there is to testing now, one more thing about this, we can actually
check our test coverage by going go test cover and it will tell me that I actually have in my testing
course here, I have 50 percent of the statements are covered and we can even get better than that.
And we can do so by running this command, which I'm going to paste in go test dashkova profile equals
coverage out, which will spitfire's up here called coverage out.
And then if that is successful, run, go to cover HTML equals coverage.
And if I run that.
It actually fires up my Web browser for me and shows me what's covered in green and what's not covered
in red.
Now, realistically speaking, a 50 percent test coverage is not great.
But the reality is we're going to, throughout the course of this course, make our main functions as
dumb as we possibly can and not bother testing them.
So we're going to do as little in here as we possibly can instead of doing a lot within our main function.
As time goes on, we'll begin to pass all of our actions off to functions and we'll test those functions.
And we just won't bother to test our main function.
And we'll get pretty, pretty good course test coverage as we go through this course.
All right.
That's it for testing.
We'll see lots more of examples of this as we begin writing more sophisticated code.