Both sides previous revisionPrevious revisionNext revision | Previous revision |
student:junit:v5 [2018/08/14 10:55] – bernstdh | student:junit:v5 [2024/01/24 16:43] (current) – bernstdh |
---|
| |
| |
===== JUnit v5 (Jupiter) Basics ===== | ===== JUnit v5 (Jupiter) Basics ===== |
</code> | </code> |
| |
(Note: The ''%%import static%%'' allows you to refer to static members in the ''%%org.junit.jupiter.api.Assertions%%'' package without having to include the class name.) | (Note: The ''%%import static%%'' allows you to refer to static members in the ''%%org.junit.jupiter.api.Assertions%%'' class without having to include the class name.) |
| |
The file //ClassName//Test.java contains methods that can be used to test the class defined in //ClassName//.java. Each such method is preceded by an ''%%@Test%%'' annotation. (Note: An annotation provides information about a program but is not part of the program. Annotations have no effect on the operation of the program. Instead, they are used to provide information to tools that might use the program as input.) | The file //ClassName//Test.java contains methods that can be used to test the class defined in //ClassName//.java. Each such method is preceded by an ''%%@Test%%'' annotation. (Note: An annotation provides information about a program but is not part of the program. Annotations have no effect on the operation of the program. Instead, they are used to provide information to tools that might use the program as input.) |
| |
| |
The body of the methods in the //ClassName//Test.java must contain the test cases for the corresponding methods in the //ClassName// class. These test cases often involve some "setup" code and a call to the ''%%Assert.assertEquals()%%'' method. So, for example, the ''%%getAtomicNumber%%'' method in the ''%%Atom%%'' class is supposed to return the atomic number of the calling ''%%Atom%%'' object. To partially test this method one might implement the ''%%testGetAtomicNumber()%%'' method in the ''%%AtomTest%%'' class as follows: | The body of the methods in the //ClassName//Test.java must contain the test cases for the corresponding methods in the //ClassName// class. These test cases often involve some "setup" code and a call to the ''%%Assertions.assertEquals()%%'' method. So, for example, the ''%%getAtomicNumber%%'' method in the ''%%Atom%%'' class is supposed to return the atomic number of the calling ''%%Atom%%'' object. To partially test this method one might implement the ''%%testGetAtomicNumber()%%'' method in the ''%%AtomTest%%'' class as follows: |
| |
<code java> | <code java> |
assertEquals(8, o.getAtomicNumber(), "Oxygen"); | assertEquals(8, o.getAtomicNumber(), "Oxygen"); |
// Note: | // Note: |
// This is a call to Assert.assertEquals() but the class name | // This is a call to Assertions.assertEquals() but the class name |
// isn't needed because of the static import. | // isn't needed because of the static import. |
} | } |
</code> | </code> |
| |
In the "setup" portion, this method creates an ''%%Atom%%'' objects (for oxygen). It then calls the ''%%Assert.assertEquals()%%'' method to tell JUnit to do some testing. This particular version of the ''%%Assert.assertEquals()%%'' method is passed three parameters and has the following syntax: | In the "setup" portion, this method creates an ''%%Atom%%'' objects (for oxygen). It then calls the ''%%Assertions.assertEquals()%%'' method to tell JUnit to do some testing. This particular version of the ''%%Assertions.assertEquals()%%'' method is passed three parameters and has the following syntax: |
| |
''Assert.assertEquals(//ExpectedValue//, //ActualValue//, //Description//);'' | ''Assertions.assertEquals(//ExpectedValue//, //ActualValue//, //Description//);'' |
| |
The //Description// is a human-readable ''%%String%%'' that provides information that enables the tester to understand the test in the event that the code fails the test. (Note that the tester will also be provided with the name of the test method so it isn't necessary to include information about the method being tested in the description if the test method is named well.) The //ExpectedValue// contains the correct value (i.e., the value that the tester expects if the method named //MethodName// in //ClassName// is working correctly. The //ActualValue// contains the value that was actually generated by the method named //MethodName// in //ClassName//. | The //Description// is a human-readable ''%%String%%'' that provides information that enables the tester to understand the test in the event that the code fails the test. (Note that the tester will also be provided with the name of the test method so it isn't necessary to include information about the method being tested in the description if the test method is named well.) The //ExpectedValue// contains the correct value (i.e., the value that the tester expects if the method named //MethodName// in //ClassName// is working correctly. The //ActualValue// contains the value that was actually generated by the method named //MethodName// in //ClassName//. |
| |
| |
==== More About the Assert.assertEquals() Method ==== | ==== More About the Assertions.assertEquals() Method ==== |
| |
| |
The ''%%Assert.assertEquals()%%'' method can be used to compare the expected and actual values of a wide variety of different types. In the examples above it is used to compare ''%%int%%'' values and ''%%boolean%%'' values. It can also be used to compare ''%%String%%'' objects and other objects, but you have to be careful when doing so. When ''%%assertEquals()%%'' is used to compare primitive types, it uses the ''%%==%%'' operator. When ''%%assertEquals()%%'' is used to compare class types, it uses the ''%%.equals()%%'' method (with special handling for ''%%null%%'' references). | The ''%%Assertions.assertEquals()%%'' method can be used to compare the expected and actual values of a wide variety of different types. In the examples above it is used to compare ''%%int%%'' values and ''%%boolean%%'' values. It can also be used to compare ''%%String%%'' objects and other objects, but you have to be careful when doing so. When ''%%assertEquals()%%'' is used to compare primitive types, it uses the ''%%==%%'' operator. When ''%%assertEquals()%%'' is used to compare class types, it uses the ''%%.equals()%%'' method (with special handling for ''%%null%%'' references). |
| |
| |
When using ''%%Assert.assertEquals()%%'' to compare floating point numbers (e.g., ''%%double%%'' values), one must remember that the ''%%==%%'' operator must be used with care because of the less-than-perfect precision of operations on ''%%double%%'' values. In JUnit, the implication of this is that one should check to see if ''%%double%%'' values are within a tolerance value of each other. Hence, when comparing ''%%double%%'' values one should use the following: | When using ''%%Assertions.assertEquals()%%'' to compare floating point numbers (e.g., ''%%double%%'' values), one must remember that the ''%%==%%'' operator must be used with care because of the less-than-perfect precision of operations on ''%%double%%'' values. In JUnit, the implication of this is that one should check to see if ''%%double%%'' values are within a tolerance value of each other. Hence, when comparing ''%%double%%'' values one should use the following: |
| |
''Assert.assertEquals(//ExpectedValue//, //ActualValue//, //tolerance//, //Description//);'' | ''Assertions.assertEquals(//ExpectedValue//, //ActualValue//, //tolerance//, //Description//);'' |
| |
| |
| |
| |
There are several ways to test for thrown exceptions in JUnit. The most common is to use the ''%%assertThrows()%%'' method. For example, suppose the constructor of the ''%%Atom()%%'' class is required to throw an ''%%IllegalArgumentException%%'' when the numeric parameters are negative. One might test this is follows. | There are several ways to test for thrown exceptions in JUnit. The most common is to use the ''%%assertThrows()%%'' method, but this approach depends on an advanced feature of Java (and many languages) called [[https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html|"lambda expressions"]], so we will demonstrate a less commonly used, but simpler, approach first. |
| |
| === Testing for exceptions === |
| |
<code java> | One can invoke the methods that is supposed to throw an expression in a ''%%try-catch%%'' block, and use the ''%%fail()%%'' method. For example: |
/** | |
* Test that the constructor validates properly. | |
*/ | |
@Test | |
public void constructor_IllegalArguments() | |
throws IllegalArgumentException | |
{ | |
assertThrows(IllegalArgumentException.class, () -> {new Atom("O", -8, -16);}); | |
} | |
</code> | |
| |
This approach uses a //Lambda expression//, a representation of a class with a single-method. | |
(Note that ''%%IllegalArgumentException%%'' is an unchecked exception. Hence, this code will compile even if the test method does not specify that it re-throws the exception. If you are testing for a checked exception then the test method must specify that it re-throws the exception.) | |
| |
| |
Alternatively, one can invoke the methods that is supposed to throw an expression in a ''%%try-catch%%'' block, and use the ''%%fail()%%'' method. For example: | |
| |
<code java> | <code java> |
| |
// Shouldn’t get here | // Shouldn’t get here |
fail("Constrcutor should have thrown an IllegalArgumentException"); | fail("Constructor should have thrown an IllegalArgumentException"); |
} | } |
catch (IllegalArgumentException iae) | catch (IllegalArgumentException iae) |
</code> | </code> |
| |
| === Testing for exceptions canonically (with lambda expressions) === |
| |
| Suppose the constructor of the ''%%Atom()%%'' class is required to throw an ''%%IllegalArgumentException%%'' when the numeric parameters are negative. One might test this is follows. |
| |
==== Other Useful Methods in the Assert Class ==== | |
| |
| <code java> |
| /** |
| * Test that the constructor validates properly. |
| */ |
| @Test |
| public void constructor_IllegalArguments() |
| { |
| assertThrows(IllegalArgumentException.class, () -> {new Atom("O", -8, -16);}); |
| } |
| </code> |
| |
The ''%%Assert%%'' class contains other useful methods including: | This approach uses a //Lambda expression//, a representation of a class with a single-method. |
| |
| ==== Other Useful Methods in the Assertions Class ==== |
| |
| |
| The ''%%Assertions%%'' class contains other useful methods including: |
| |
''%%assertArrayEquals()%%'' for arrays of different types\\ | ''%%assertArrayEquals()%%'' for arrays of different types\\ |
The .jar file will be named something like ''%%junit-platform-console-standalone.jar%%'' (which is referred to below as ''%%junit.jar%%'' for simplicity). | The .jar file will be named something like ''%%junit-platform-console-standalone.jar%%'' (which is referred to below as ''%%junit.jar%%'' for simplicity). |
| |
==== Compiling and Running JUnit Tests from a Command Shell ==== | ==== Compiling and Running JUnit Tests from a Command Shell/Terminal Window ==== |
| |
| |
To run: | To run: |
| |
''java -cp .;junit.jar org.junit.platform.console.ConsoleLauncher --select-class //ClassName//Test'' | ''java -cp .:junit.jar org.junit.platform.console.ConsoleLauncher --select-class //ClassName//Test'' |
| |
where //Name// represents the name of the class being tested. | where //Name// represents the name of the class being tested. |
To compile: | To compile: |
| |
''javac -cp .;junit.jar //ClassName//Test.java'' | ''javac -cp .:junit.jar //ClassName//Test.java'' |
| |
where //Name// represents tha name of the class being tested (and can contain wildcards like *). | where //Name// represents tha name of the class being tested (and can contain wildcards like *). |
To run: | To run: |
| |
java -cp .;junit.jar org.junit.platform.console.ConsoleLauncher --select-class //ClassName//Test | java -cp .:junit.jar org.junit.platform.console.ConsoleLauncher --select-class //ClassName//Test |
| |
where //Name// represents the name of the class being tested. | where //Name// represents the name of the class being tested. |
| |
<code> | <code> |
javac -cp .;junit.jar AtomTest.java | javac -cp .:junit.jar AtomTest.java |
java -cp .;junit.jar org.junit.platform.console.ConsoleLauncher --select-class AtomTest | java -cp .:junit.jar org.junit.platform.console.ConsoleLauncher --select-class AtomTest |
</code> | </code> |
| |
| |
| |
==== Integrating JUnit into a IDE ==== | ==== Integrating JUnit into an IDE ==== |
| |
| |