Let's take a look at some unit testing.
Unit testing allows you to write code to test your assumptions
with your live code.
So, for instance, if we had 'def greeting', and we wanted it
to return "hello" every single time. We could write a test,
an automated test to make sure that it always returns "hello".
Now, that's an overly simplistic example.
But nonetheless, that's important.
So the goal is to really send data to your program, analyze
the results of the program, and see if it gives you the expected
result. So basically, we throw this into, like, a another
program, for instance, and it's going to test 'greeting', and
it's going to make sure that it says, '"hello".
And if it doesn't, it's going to raise some sort of error
and let us know that something's changed.
Our test has broken.
Now, this is actually a really good way to build confidence
in your programs and to help reduce errors that users or
other developers might introduce in the future.
So especially when you're writing code with other people,
you might want to write unit tests because you do not
necessarily know if they're going to be changing your function.
Maybe their function changes from "hello" to returning "hi".
And your unit test is going to say, "No, it's supposed to say
hello. Something broke.
Someone broke something".
So for tests, we're actually going to need to know a little
bit of Object Oriented Programming.
So if you need a little refresher on that, definitely head
back to the OOP section, and give those videos a quick watch
once again, and then feel free to jump back over here.
If you feel like you're good enough with Object Oriented
Programming, let's just jump right into this.
So first, we need to create two scripts, and before I do
that, I'm going to throw this into a folder called 'Unit Testing'.
And in here I'm going to create my first script, and this
one is going to be called 'my_program.py'
And the second one I'm going to call is 'tests.py'.
So I'm going to have a program in here, and all it's going
to do is change some text to make it uppercase.
So I'm going to create a new function, 'make_it_uppercase',
and it's going to take some text, and all it's going to do
is return that 'text.upper()'.
And so the idea here in a Docstring, we could write "ie.
"hello world", and it's going to output "HELLO WORLD" as if it's
yelling at us. Now in our test.py file
we want to import this.
We want to, 'from my_program import', what did I call that?
'make_it_uppercase'.
We also need to 'import unittest' entirely.
We're not going to do 'from unittest import' something.
We're just going to import all of unittest.
So now we need to create a class.
The class is going to be 'TestMyProgram',
that's what it's going to be called, and this uses class inheritance.
So we're going to use 'unittest.TestCase'.
[no audio]
And in here we can write all of our tests.
So we want to start our test with the word 'test'.
So 'test', what are we testing? Let's 'test_hello_world'.
And because this is an object, and this is a method, it always
takes 'self' as its first parameter.
So in here we could say 'text = make_it_uppercase("hello world")'.
And we know that if things are running properly, it will
turn "hello world" into all caps, "HELLO WORLD".
And now we can do this thing called an assertion.
So we can do 'self.assertEqual',
or actually, there's quite a few of them in here,
you can see this with VS code
it's automatically popping this up for me.
So we could do 'assertNotEqual', 'assertLess', 'assertList'.
We could do all sorts of things, but we just want to
'assertEqual', and it's going to take two parameters.
It's going to take our result,
actually let's call this 'result', and it's going to take our
assumption, which is going to be "HELLO WORLD".
Now, at the bottom of our tests, we can do 'if __name__ ==
"__main__": unittest.__main__'.
So if this script is being called by Python not as an import,
but as an actual program, automatically take 'unittest' and
run '__main__', and that's going to run our tests here.
So let's go ahead.
'cd../', upper directory, 'cd' into, what did I call this, 'Unit\ Testing/'
'ls -la' or 'dir' if you're on Windows,
and let's do 'python tests.py',
And look at that.
I actually have a little bit of an error here.
'make_it_uppercase' on 'Unit Testing',
'my_program.py', line 2.
And if you're screaming at your screen saying, "Kalob, you
missed your your colon there", good catch.
If not, that's okay, because I didn't catch it either.
Let's go ahead and rerun this.
"Ran 1 test in zero seconds",
that's how fast it is.
And it was okay.
Now let's say someone down the line was working with our
code and they said, "Make it uppercase,
maybe we actually just want to make the first letters upper
case and everything else could be lower case".
So we could use 'title()'.
Let's rerun our test and see what happens.
Because if we run 'title', it's not going to print HELLO WORLD
in all caps anymore.
[no audio]
And look at this. Here it is.
F is for failure.
It failed that 'test_hello_world' on 'TestMyProgram'.
That's over here.
'TestMyProgram'.
There's a trace back, which is going to give you all sorts of details.
So in 'test.py' on line 9, 'test.py', line 9,
[no audio]
the assertEqual' failed,
and it was looking for this,
'Hello World!' != 'HELLO WORLD'',
one is all caps,
one just has the first letter capitalized of each word.
What it got, what it was expecting.
And so now we have a failure in here.
Now let's go ahead and create another test.
Let's do one a little more complicated.
Let's do 'def get_first_word()' from a sentence, and it's going
to take a 'sentence', and all it's going to do is get the first
word. So let's try something here, 'return sentence.split()'
on a space, and let's return the first one.
Because we know that this is going to be a list,
we can just automatically return the first one. If you want
to you can always split this on two different lines as well.
You could say something like 'words =', and then
you could just return the first word.
And that's okay, too.
So let's go ahead and create another test in here.
First, we need to import this, 'get_first_word'. Let's go ahead and
import a second import here from that same file called 'my_program'
'def test_first_word', and it's going to take 'self'.
Now let's go ahead and say the 'sentence' is going to be is
some 'Lorem Ipsum' stuff.
And so it's a fairly long sentence, and we are expecting
it to return just this word.
So now we can take that 'sentence', apply it.
So 'result = get_first_word', throw the 'sentence'
in there, and we can 'self.assertEqual(result)', and
that 'result' what we're expecting is supposed to be that first word,
exactly that first word, not uppercase, not lowercase, just the
first word. Now we can go ahead and run this.
[no audio]
Let's try this again.
And I have run two tests in here in 0.001 seconds, and one failure,
and that was because I didn't change that one back.
Let's rerun this and there are no problems.
Let's make this just a tad bigger here.
So this is doing exactly what we thought it would do.
What if, however, let's say this isn't 'test_first_word', this
is going to be 'test_first_word_in_sentence()'.
Now a unit test
we have to try to figure out all these other different use
cases. So let's say 'test_first_word_in_sentence_with_one_word',
and we're only going to provide one word in here, just
the word "Lorem".
And what we're testing here is to see if this fails.
So let's go ahead and run this once more.
Cool.
So that was okay.
But what if, for whatever reason, I just forgot to return
the first word, and I just returned the whole list? Again,
just read that 'Traceback',
and it's going to say in, file "test.py" on line 19 with this
long function here,
what it got was a list with 'Lorem' as the first item compared to a string.
So either the test was wrong or the function was wrong.
Okay, let's try one more just for funsies.
Let's try something that's not a string.
Let's create a new function in here, and this one is just
going to 'return_a_list', and it's not going to take anything,
because I want this to be a faster example.
And all this is going to do is return a list of ['Cats', 'Dogs', Birds'].
[no audio]
And we can write another test in here to make sure
that that is what it's supposed to be.
So let's grab this and just copy that.
[no audio]
Go over here and paste it.
So we're importing all three functions from 'my_program,py',
and let's test the list.
Let's do a test,
return a list, always take 'self' because it's in an object,
this object that's inheriting from 'unittest.TestCase'.
And we want to make sure that the list, let's call it 'result'.
I like calling it 'result',
it doesn't have to be called 'result'.
So just make sure 'result = return_a_list',
and we know that that is supposed to return this,
and we can try a different assert.
We can do 'self.assertListEqual',
and you can actually see VS Code is being nice here.
It's saying the first item has to be a list, any type of
list. The second item has to be a list, any sort of message.
So the 'result' is the first one
we're going to compare against the second one here.
And if it doesn't work out, let's give it an error message.
"THE LIST WAS WRONG".
And let's put these on separate lines just to keep this a
little cleaner.
Let's go ahead and run this test.
[no audio]
Hey, cool. That worked.
What if somewhere down the road, someone said, "We're gonna
change 'Cats', to 'Kitties', and 'Dogs'
to 'Doggos' and 'Birds' are just going to be 'Birds'.
[no audio]
Let's go ahead and run this.
Now we're going to see a different type of error.
We're seeing that this list does not match the expected list.
So this is what we got,
and this is what the 'unittest' was expecting.
It even tells us 'First differing element at 0'.
'Kitties'. Was 'Kitties' and 'Cats'.
So I thought, 'Kitties' and 'Cats' are not the same.
It's right. It's not the same.
So we could go ahead and we could change that back.
And this one is now going to complain about Doggos'.
'First differing element is 'Doggos', and 'Dogs'.
Okay, let's change that one back.
That one's supposed to be 'Dogs', and voila.
We have four 'unittest' up and running the way we expect them to.
[no audio]