Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
student:junit:v5 [2018/08/14 10:45] – created bernstdhstudent:junit:v5 [2024/01/24 16:43] (current) bernstdh
Line 1: Line 1:
- 
  
 ===== JUnit v5 (Jupiter) Basics ===== ===== JUnit v5 (Jupiter) Basics =====
Line 45: Line 44:
 </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.)
Line 66: Line 65:
  
  
-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>
Line 81: Line 80:
         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//.
Line 133: Line 132:
  
  
-==== 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//);''
  
  
Line 147: Line 146:
  
  
-There are several ways to test for thrown exceptions in JUnit. The most common is to use the ''%%assertThrows()%%'' method. For examplesuppose   the constructor of the ''%%Atom()%%'' class is required to throw an   ''%%IllegalArgumentException%%'' when the numeric parameters   are negativeOne 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 languagescalled [[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>
Line 180: Line 164:
  
       // 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)
Line 189: Line 173:
 </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> 
 + 
 +This approach uses a //Lambda expression//, a representation of a class with a single-method.  
 + 
 +==== Other Useful Methods in the Assertions Class ====
  
  
-The ''%%Assert%%'' class contains other useful methods including:+The ''%%Assertions%%'' class contains other useful methods including:
  
 ''%%assertArrayEquals()%%'' for arrays of different types\\ ''%%assertArrayEquals()%%'' for arrays of different types\\
Line 224: Line 224:
  
  
-==== The @Before Annotation ====+==== The @BeforeEach and @BeforeAll Annotations ====
  
  
Line 230: Line 230:
  
  
-The ''%%@Before%%'' annotation is very useful when   an individual test changes the state of an object since, in general,   one wants test to be independent. (Note that, in general, you should   not assume that the tests themselves will be run in a particular order.)+The ''%%@BeforeEach%%'' and ''%%@BeforeAll%%'' annotations are very useful when   an individual test changes the state of an object since, in general,   one wants test to be independent. (Note that, in general, you should   not assume that the tests themselves will be run in a particular order.)
  
 To use these annotation you must import ''%%org.junit.jupiter.api.BeforeEach%%'' and/or To use these annotation you must import ''%%org.junit.jupiter.api.BeforeEach%%'' and/or
Line 240: Line 240:
  
 Information about how to download and install JUnit is available   from   [[ https://github.com/junit-team/junit/wiki/Download-and-Install | junit.org ]]. Information about how to download and install JUnit is available   from   [[ https://github.com/junit-team/junit/wiki/Download-and-Install | junit.org ]].
 +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/Terminal Window ====
-==== Compiling and Running JUnit Tests from a Command Shell ====+
  
  
Line 262: Line 262:
  
 <code bash> <code bash>
-export CLASSPATH=.://directory//junit.jar://directory//hamcrest-core.jar:$CLASSPATH+export CLASSPATH=.://directory//junit.jar:$CLASSPATH
 </code> </code>
  
-where //directory// denotes the name of the directory/folder that contains the files ''%%junit.jar%%'' and ''%%hamcrest-core.jar%%''.+where //directory// denotes the name of the directory/folder that contains the file ''%%junit.jar%%''.
  
-For example, assuming that the two ''%%.jar%%'' fiels are in the current working directory, you can set the ''%%CLASSPATH%%'' as follows:+For example, assuming that the ''%%.jar%%'' file is in the current working directory, you can set the ''%%CLASSPATH%%'' as follows:
  
 <code bash> <code bash>
-export CLASSPATH=.:junit.jar:hamcrest-core.jar:$CLASSPATH+export CLASSPATH=.:junit.jar:$CLASSPATH
 </code> </code>
  
Line 276: Line 276:
  
 <code bash> <code bash>
-java org.junit.runner.JUnitCore //ClassName//Test+java org.junit.platform.console.ConsoleLauncher --select-class  //ClassName//Test
 </code>  </code> 
 +
  
 where //ClassName// is the name of the class being tested. For example, to run ''%%AtomTest%%'': where //ClassName// is the name of the class being tested. For example, to run ''%%AtomTest%%'':
  
 <code> <code>
-java org.junit.runner.JUnitCore AtomTest+java org.junit.platform.console.ConsoleLauncher --select-class  AtomTest
 </code> </code>
  
Line 301: Line 302:
 To run: To run:
  
-''java -cp .:junit.jar:hamcrest-core.jarorg.junit.runner.JUnitCore //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.
Line 309: Line 310:
 <code bash> <code bash>
 javac -cp .:junit.jar AtomTest.java javac -cp .:junit.jar AtomTest.java
-java -cp .:junit.jar hamcrest-core.jarorg.junit.runner.JUnitCore AtomTest+java -cp .:junit.jar org.junit.platform.console.ConsoleLauncher --select-class   AtomTest
 </code> </code>
  
Line 325: Line 326:
  
  
-The Java compiler needs to be able to "find" the JUnit classes and the Java intepreter needs to be able to find both the JUnit classes and the Hamcrest classes. For this discussion, we will assume that the JUnit classes are in ''%%junit.jar%%'' and the Hamcrest classes are in ''%%hamcrest-core.jar%%'' (though the actual names will vary). You can either identify the location of these files each time you use the compiler/interpreter or you can set an operating system environment variable named ''%%CLASSPATH%%''.+The Java compiler needs to be able to "find" the JUnit classes and the Java intepreter needs to be able to find the JUnit classes. For this discussion, we will assume that the JUnit classes are in ''%%junit.jar%%'' (though the actual names will vary). You can either identify the location of these files each time you use the compiler/interpreter or you can set an operating system environment variable named ''%%CLASSPATH%%''.
  
  
Line 333: Line 334:
 You can set the ''%%CLASSPATH%%'' as follows: You can set the ''%%CLASSPATH%%'' as follows:
  
-''set CLASSPATH=.;//directory//junit.jar;//directory//hamcrest.jar;%CLASSPATH%''+''set CLASSPATH=.;//directory//junit.jar;%CLASSPATH%''
  
-where //directory// denotes the name of the directory/folder that contains the files ''%%junit.jar%%'' and ''%%hamcrest-core.jar%%''.+where //directory// denotes the name of the directory/folder that contains the file ''%%junit.jar%%''.
  
-For example, assuming that the two ''%%.jar%%'' files are in the current working directory, you can set the ''%%CLASSPATH%%'' as follows:+For example, assuming that the ''%%.jar%%'' file is in the current working directory, you can set the ''%%CLASSPATH%%'' as follows:
  
 <code> <code>
-set CLASSPATH=.;junit.jar;hamcrest-core.jar;%CLASSPATH%+set CLASSPATH=.;junit.jar;%CLASSPATH%
 </code> </code>
  
 After you have set the ''%%CLASSPATH%%'' you can compile your classes (including the test classes) and the usual way, and run a JUnit test as follows: After you have set the ''%%CLASSPATH%%'' you can compile your classes (including the test classes) and the usual way, and run a JUnit test as follows:
  
-java org.junit.runner.JUnitCore //ClassName//Test+java  org.junit.platform.console.ConsoleLauncher --select-class   //ClassName//Test
    
 where //ClassName// is the name of the class being tested. For example, to run ''%%AtomTest%%'': where //ClassName// is the name of the class being tested. For example, to run ''%%AtomTest%%'':
  
 <code> <code>
-java org.junit.runner.JUnitCore AtomTest+java  org.junit.platform.console.ConsoleLauncher --select-class   AtomTest
 </code> </code>
  
Line 362: Line 363:
 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 *).
Line 368: Line 369:
 To run: To run:
  
-java -cp .;junit.jar;hamcrest-core.jarorg.junit.runner.JUnitCore //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.
Line 375: Line 376:
  
 <code> <code>
-javac -cp .;junit.jar;hamcrest-core.jar AtomTest.java +javac -cp .:junit.jar AtomTest.java 
-java -cp .;junit.jar;hamcrest-core.jarorg.junit.runner.JUnitCore AtomTest+java -cp .:junit.jar org.junit.platform.console.ConsoleLauncher --select-class   AtomTest
 </code> </code>
  
Line 386: Line 387:
  
  
-==== Integrating JUnit into IDE ====+==== Integrating JUnit into an IDE ====