[MUSIC]
>> Greetings, everyone. Welcome back to
Microsoft Java for beginner series.
My name is Brian Benz and I'm a Cloud Advocate at Microsoft.
I'm joined by Oleg Šelajev.
Oleg is going to tell us about Java testing.
Oleg, do you want to introduce yourself
and tell us about the topic?
>> Hi, everyone. Thank you, Brian.
My name is Oleg, and I work for AtomicJar,
which is a company created by
the maintainers of Testcontainers Java library,
which is the integration testing library.
That is really, really good.
Today we're going to talk about
unit tests and how you can
write your first test for your Java application.
We're going to introduce and look at the JUnit framework.
I think this is an essential skill for any developer and hope
you're going to learn the basics and then
successfully applied that in your career.
What does it mean to write test and test of our application?
Our application consists of code and it's
written in Java or any other JVM languages.
But in an actual, this is
the functionality that describes how our app needs to behave.
Now, the tests for the functionality are also
code which is structured with a very precise purpose.
We want to write code that verifies how our business logic,
how our application works.
For that, we need these three essential things,
which is set up the environment and assumptions,
then we need to run the app,
and we need to run the code,
and then verify the results.
This is exactly what we want to do.
Now, we're going to write this in
Java and I'm going to show you how you can
write your first test using the JUnit framework.
Different languages sometimes include the SDK for
writing unit tests in the base package.
Java is not like that.
Java does not have a library for writing
tests included in the standard library,
you need to include that separately.
This gives you a great flexibility
for what library you want to choose.
We're going to go with the default one.
This is a Maven project.
We're going to include the dependency on the JUnit library.
JUnit is the name of the library that we're going
to use in our pom.xml.
If you want to learn more about Maven and built tools,
please consult another video in this playlist.
We're going to have a dependency,
and we're going to have a dependency on
JUnit and the artifact called JUnit Jupiter,
which is the umbrella parent artifact
for the JUnit dependencies that we need to pull.
We're going to identify that we
will pull this only into the test scope,
so only for the test that will be included.
But now we'll have the access to the JUnit classes.
In order to make Maven aware that we want to run tests,
we need to include the plugin that will locate
our test and run it at the part of the build lifecycle.
For that, we include a plugin into the plugins management system,
and we include the maven-surefire-plugin was a modern version.
That's going to go great and they are both compatible,
so we're going to run with this.
Now by convention, our tests will be located in
a source test directory and I'm going to
follow the same structure as
the source main Java package name class name,
we're going to have source test
Java package name application tests.
Make sure that your class ends with test or tests.
That is the convention for the surefire plugin to
find your tests and run them automatically.
Any test class and any test method can be a test.
To turn that, we need to annotate that
with a test annotation from JUnit.
We're going to do exactly that.
You can immediately see that my IDE
figured out this is a test class,
and now I can run this.
When I click "Play" and it would Run verifyStuffWorks.
What will happen is my IDE will build the class by some of
the project and it will run the code in this particular test.
If I would like to run that using the build tool,
I can just run Maven test phase command in any terminal.
So it will package my project.
It will run the test.
It will start using the surefire plugin
that we included. Let me show you.
It runs the surefire.junitplatform provider for the test,
and it prints a little summary of the test results.
Tests can be in several states.
It found our one test that we want to run,
and it says that it run it and it run successfully.
There could be a successful test run, a failure,
which means that the assumptions of the tests or
assumptions about the behavior and
verifying the results didn't work.
Error, which means that the test broke,
maybe through unwanted exceptions or anything,
or to test could be skipped.
We can run tests from the command line or we can
run tests from our IDE, whatever that is.
You can run tests and JUnit tests
are the de facto standard in the Java ecosystem,
so all IDEs will work.
I'm running here IntelliJ IDEA.
You can run in VS Code, Eclipse IDE,
NetBeans, on any browser IDE, whatever you want.
Now we can run this test.
Let's verify that our application works as expected.
Setting up the environment is easy.
We would like to create the objects that we want
to run code off and then we can verify the behavior.
We can create the new app
and we're going to say that it has the offset of zero.
It's going to be an app variable.
Then what we can do? We can say app.add,
say, 2 plus and 42 at two integers,
this will produce a result that we can here,
let's call it the result, actualResult.
Then what we need to do in a test,
we need to verify that these results actually corresponds to
our understanding what the app has to do.
Say for expected value,
let's say, int expected value is 42 for this particular use case.
Now we would like to run something akin to
the type if expected equals actualResult,
then pass the test,
and else we need to fail the test.
Now failing the test means that we can throw an exception
which the surefire plugin and the JUnit by
default will consider a test in error.
If our testers throw unexpected exceptions,
it might mean not just the application didn't work as we expected,
but it means that application got
broken when we actually try to use it.
You can cover the code pass,
which throw exception was a little
bit more advanced during the features.
But for the initial first test
that you want to run, you don't have to.
Instead of verifying code like this, what do we going to use?
We're going to use the assertions library from JUnit itself.
We're going to say Assertions.assertEquals,
and here we're going to have the expected outcome
and the actual result.
Now, the assertions will correspond to running the test.
Then if the assertion is actually
correct and we could have there are multiple methods.
For assertions, you can see there assertEquals, or assertTrue,
or assert that they call throws, or assertFalse.
All the good stuff. You can have a number of assertions in a test.
But the first assertion that fails,
can fail the test. Let's see that.
First, we're going to see whether
the expected actual results are correct.
Let's run this test. Let's verify stuff works.
Here's the interesting thing.
You can call your method name something more legible and readable.
For example, let's call it verifyAddingPositiveNumbersWorks.
Then in the test result,
we would see a much more telling them here.
Of course, our test doesn't pass.
It throws the assertion error.
It shows that a yellow marker in
my IDE means that the test failed.
Of course why it failed, because when we add 2 and 42, we get 44.
Let's change it to have the correct behavior.
We could have changed the expected result and add the same.
But we can also play with the parameters here.
Now if we rerun this test, it will work.
It will show us a green checkbox that our test works,
and then it will work.
We tried to rerun the test,
but since we changed the name of the method,
they didn't find the previous one.
The test works, the assertion passes. Very, very good.
Now, JUnit is a very flexible framework
and you can create, of course,
multiple test cases in
the same class and you can
also run the multiple tests at the same time,
so we can run app tests or we can run it
with a common line using the Maven command,
and it will run all the tests that it automatically discovers.
You can configure everything,
but you don't have to do that besides the basic things.
Now, if you don't
want every single test case to repeat setting up the environment,
what you can do, you can
specify the lifecycle message for the tests,
which are very, very convenient.
What you can do, we can say we can mark
a test was the lifecycle annotations.
For example, before all or before each.
What we can do is we can create
this static method that will do the setup for us.
For example, we can say the app equals new app with the offset,
and we can create the static field in this particular class.
Now, the JUnit will execute our before all method,
before all the tests within the class so we
can only run one instance of this application.
I can even show you.
If we go into the app and,
say, change the code to, say,
hello creating an app with the offset and plus offset,
and we can run the test.
We're going to see that only one instance of the app is created
very early in this process and it was just done.
Now in the test again, what I can do,
I can also create the environment for running
the test before every test.
Say, I will have the private int N equals 0, doesn't matter.
I'm going to do the n plus plus thing.
All the time, we're going to create a new app,
we're going to increment offset.
Then if we want to have it before each,
we don't have actually the field to be static,
so we can have the instance methods.
I'm going to run now and now we're going to create
a new app for every test in
creating the offset and it will
work beautifully creating two apps.
This is how you can build extensive tests
to use for your application.
In general, you want to test for multiple scenarios
for a happy pass where everything works as expected.
For unhappy pass where arguments are less fortunate, for example,
checking for nulls if you have nulls acceptable in your API,
or you can do all kinds of tests to verify the behavior.
Your IDE and your tooling will help with every step.
You will be able to run your test from your IDE.
You will be able to verify and
run your test from your command app.
If we run the tests again, now,
I would expect Maven to find two tests and run them again.
That is how you write your unit tests for your Java application.
>> Thanks, Oleg. That was really great.
Please check out the rest of the topics
in Microsoft Java for beginner series.
>> Thank you.
[MUSIC]