JUnit is a regression testing framework written by Erich Gamma and Kent Beck. Junit test is a programmer test, i.e. a white box test. The project homepage: http://www.junit.org/
When using JUnit, you mainly write test cases by inheriting the TestCase category, and use the testXXX() name to write unit tests.
There are three things that really need to write tests with JUnit:
1. An import statement introduces all classes under junit.framework.*.
2. An extends statement allows your class to inherit from TestCase.
3. A constructor that calls super(string).
Functional MathTool
package com.zj.c01;public class MathTool { public static int gcd(int num1, int num2) { int r = 0; while (num2 != 0) { r = num1 % num2; num1 = num2; num2 = r; } return num1; } }Test class MathToolTest
package com.zj.c01;import junit.framework.TestCase; public class MathToolTest extends TestCase { public MathToolTest(String name) { super(name); } public void testGcd() { assertEquals(5, MathTool.gcd(10, 5)); } } When we use JUnit to test exceptions, the easiest way to think of is to use try...catch to catch the exception. We need to assert the following conditions:
1. Exception that is indeed thrown 2. Class type of the exception thrown 3. The specific type of the exception is thrown. Generally, check the determination of the string contained in the message attribute of the exception. So you may write the common code like this:
@Test public void testBizException(){ try{ Password.validate( "123" ); fail( "No exception thrown." ); }catch ( Exception ex ) { assertTrue( ex instanceof BizException ); assertTrue( ex.getMessage().contains( "error" ) ); } } The method tested here is whether the Password.validate() method throws the corresponding exception. Please note that fail("No Exception thrown.") in the try is not missed here.
Line of code, otherwise if the method being tested does not throw an exception, this use case will pass, and what you expect is to throw an exception.
In JUnit 4, there is no need to test method exceptions like this. Although this can also determine whether the expected exception is executed, it still has disadvantages. You will know after comparing it. JUnit cannot show you the detailed reason for the assertion failure in the try...catch method.
So let’s take a look at how to test exceptions since JUnit 4? Just use @Test(execpted=Exception.class) annotation, refer to the following code:
@Test( expected = BizException.class ) public void testBizException(){ Password.validate( null ); }
If the method being tested has the BizException type thrown, the assertion is successful. By the way, @Test(expected = BizException.class) can only determine the type of the exception, and there is no corresponding annotation to assert more specific information about the exception, that is, it cannot determine the message attribute of the thrown exception.
Then, sometimes we will throw an exception of one type multiple times in a method, but the reasons are different, that is, the message information of the exception is different. For example, when a BizException occurs, there will be the following two exceptions:
new BizException("Password must contain at least 6 letters.") new BizException("Password length less than 15 letters") This requires a way to assert exception message. For this reason, since JUnit 4.7, we have given a more perfect choice, which is the following code:
@Rule public ExpectedException expectedEx = ExpectedException.none(); @Test public void testBizException() throws InvalidPasswordException{ expectedEx.expect( BizException.class ); expectedEx.expectMessage( "required" ); Password.validate( "" ); } The above code needs to be focused on:
1. @Rule annotated ExpectedException variable declaration, it must be public
2. At @Test, it cannot be written as @Test(expected=BizException.class), otherwise it cannot be tested correctly. That is, the @Test(expected=BizException.class) and the expectedEx.expectXxx() method in the test method cannot coexist at the same time. 3. The parameters in expectedEx.expectMessage() are Matcher or subString, which means that regular expressions can be used to determine, or determine whether a substring is included. 4. Another thing is very heavy, write the tested method behind the expectedEx.expectXxx() method, otherwise the exception that cannot be tested correctly 5. The last one is that as long as the test method directly throws the exception of the method being tested, it will not affect the exception you are concerned about. As mentioned earlier, using the try…catch method can also correctly test the exception. What are the benefits of comparing the @Test(expected=…) or @Rule and try…catch method? Obviously, the method recommended by JUnit 4 is concise and clear. Let’s look at what JUnit will prompt you when the test fails?
The prompt you get when the test failed abnormally:
When there is no exception:
java.lang.AssertionError: No exception thrown. at org.junit.Assert.fail(Assert.java:91) at cc.unmi.PasswordTest.passwordLengthLessThan6LettersThrowsException(PasswordTest.java:20)
When the exception type is wrong or the exception message is wrong:
java.lang.AssertionError: at org.junit.Assert.fail(Assert.java:91) at org.junit.Assert.assertTrue(Assert.java:43) at org.junit.Assert.assertTrue(Assert.java:54) at cc.unmi.PasswordTest.passwordLengthLessThan6LettersThrowsException(PasswordTest.java:22)
The above help for positioning errors is not particularly great. Look at the prompts when the test fails when @Test(expected=BizException.class):
java.lang.AssertionError: Expected exception: cc.test.BizException at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:32) at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:110)
Use @Rules ExpectedException to test exceptions. Tips when failure:
java.lang.AssertionError: Expected: (exception with message a string containing “YES. required” and an instance of java.lang.NullPointerException) got: at org.junit.Assert.assertThat(Assert.java:778) at org.junit.Assert.assertThat(Assert.java:736) at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:114)
Especially the @Rules ExpectedException method is clearly aware of why the test failed. What exception is expected, what string is contained in the exception message, what type of exception is actually obtained, and what is the message in the exception. With this, you will know how to fix your program as soon as you see it.