JUnit是一個開源的 Java 單元測試框架,它使得組織和運行測試代碼變得非常簡單,利用JUnit可以輕松地編寫和執(zhí)行單元測試,并且可以清楚地看到哪些測試成功,哪些失敗
JUnit 還提供了生成測試報告的功能,報告不僅包含測試的成功率,還能統(tǒng)計被測試代碼的覆蓋率。通過進行單元測試,我們可以確保每個方法按照預(yù)期正確運行。
如果我們修改了某個方法的代碼,只需要確保相應(yīng)的單元測試通過,就可以認為修改是正確的。此外,測試代碼本身也可以作為示例代碼,用于演示如何調(diào)用該方法。
幾乎所有的IDE工具都集成了JUnit,我們這里使用IDEA
參考?編寫JUnit測試 - 廖雪峰的官方網(wǎng)站 (liaoxuefeng.com)
目錄
編寫JUnit單元測試
使用Fixture自動執(zhí)行代碼
異常測試
條件測試
參數(shù)化測試
編寫JUnit單元測試
用遞推的方法寫一個計算n的階乘的Java方法。
我們可以針對剛剛寫的Java編寫一個對應(yīng)的測試代碼對其進行測試,在IDEA中可以直接右擊點擊生成Junit測試。
點擊確定生成一個FactorialTest.java文件。
這是JUnit會把帶有@Test的方法識別為測試方法,因此需要給測試方法加上@Test注解,測試方法內(nèi)部用assertEquals(1, Factorial.fact(1))表示期望Factorial.fact(1)返回1。
運行這個測試程序,JUnit就會給出成功的測試和失敗的測試,還可以生成測試報告,不僅包含測試的成功率,還可以統(tǒng)計測試的代碼覆蓋率,即被測試的代碼本身有多少經(jīng)過了測試。
?Factorial.java
public class Factorial {
public static long fact(long n) {
long r = 1;
for (long i = 1; i <= n; i++) {
r = r * i;
}
return r;
}
}
?FactorialTest.java
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class FactorialTest {
@Test
void testFact() {
assertEquals(1, Factorial.fact(1));
assertEquals(2, Factorial.fact(2));
assertEquals(6, Factorial.fact(3));
assertEquals(3628800, Factorial.fact(10));
assertEquals(2432902008176640000L, Factorial.fact(20));
}
}
使用Fixture自動執(zhí)行代碼
Fixture是JUnit提供的編寫測試前準備、測試后清理的固定代碼,可以用于測試前和測試后自動執(zhí)行代碼。
先編寫一個簡單的實現(xiàn)加減法功能的Calculator代碼。
但是測試的時候,需要先初始化對象,可以使用@BeforeEach和@AfterEach標(biāo)記的方法,@BeforeEach標(biāo)記的方法會在執(zhí)行每個@Test的方法之前調(diào)用,而@AfterEach標(biāo)記的方法會在執(zhí)行每個@Test的方法之后調(diào)用,這樣就可以通過@BeforeEach和@AfterEach標(biāo)記來自動實現(xiàn)對象的生成和銷毀。
然后再編寫我們的測試代碼。
運行測試代碼,可以看到測試結(jié)果。
如果需要在所有@Test方法運行前后僅運行一次,那么可以使用@BeforeAll和@AfterAll對方法進行標(biāo)記。
?Calculator.java
public class Calculator {
private long n = 0;
public long add(long x) {
n = n + x;
return n;
}
public long sub(long x) {
n = n - x;
return n;
}
}
?CalculatorTest.java
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
public class CalculatorTest {
Calculator calculator;
@BeforeEach
public void setUp() {
this.calculator = new Calculator();
}
@AfterEach
public void tearDown() {
this.calculator = null;
}
@Test
void testAdd() {
assertEquals(100, this.calculator.add(100));
assertEquals(150, this.calculator.add(50));
assertEquals(130, this.calculator.add(-20));
}
@Test
void testSub() {
assertEquals(-100, this.calculator.sub(100));
assertEquals(-150, this.calculator.sub(50));
assertEquals(-130, this.calculator.sub(-20));
}
}
異常測試
對于可能拋出的異常進行測試是測試的重要環(huán)節(jié),因此在編寫JUnit測試的時候,除了正常的輸入輸出,還要特別針對可能導(dǎo)致異常的情況進行測試。
在計算階乘的方法中增加對參數(shù)n的檢查,如果n為負數(shù),則直接拋出異常IllegalArgumentException。
在測試代碼中,我們可以編寫一個@Test方法專門測試異常,JUnit提供assertThrows函數(shù)來期望捕獲一個指定的異常。
運行測試代碼,可以看到測試結(jié)果。
?Factorial.java
public class Factorial {
public static long fact(long n) {
if (n < 0) {
throw new IllegalArgumentException();
}
long r = 1;
for (long i = 1; i <= n; i++) {
r = r * i;
}
return r;
}
}
?FactorialTest.java
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class FactorialTest {
@Test
void testFact() {
assertEquals(1, Factorial.fact(1));
assertEquals(2, Factorial.fact(2));
assertEquals(6, Factorial.fact(3));
assertEquals(3628800, Factorial.fact(10));
assertEquals(2432902008176640000L, Factorial.fact(20));
}
@Test
void testNegative() {
assertThrows(IllegalArgumentException.class, () -> {
Factorial.fact(-1);
});
}
}
條件測試
條件測試可以在滿足某種條件下執(zhí)行某些測試方法,不執(zhí)行某些測試方法。
編寫一個程序,該程序中的方法在Windows上跑和在Linux上跑的代碼路徑不同。
編寫測試代碼的時候,用@EnableOnOs標(biāo)記方法,指定只有在特定系統(tǒng)下才執(zhí)行該測試方法。
用@DisabledOnOs標(biāo)記方法表示不在某個系統(tǒng)上執(zhí)行該方法。
用@DisabledOnJre標(biāo)記方法表示只能在高于特定Java版本的測試。
用@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")標(biāo)記,表示只能在64位操作系統(tǒng)上執(zhí)行的測試。
用@EnabledIfEnvironmentVariable標(biāo)記方法表示需要傳入環(huán)境變量DEBUG=true才能執(zhí)行的測試。
運行測試代碼,可以看到測試結(jié)果。
?Config.java
public class Config {
public String getConfigFile(String filename) {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
return "C:\\" + filename;
}
if (os.contains("mac") || os.contains("linux") || os.contains("unix")) {
return "/usr/local/" + filename;
}
throw new UnsupportedOperationException();
}
}
?ConfigTest.java
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.*;
public class ConfigTest {
Config config;
@BeforeEach
public void setUp() {
this.config = new Config();
}
@AfterEach
public void tearDown() {
this.config = null;
}
@Test
@EnabledOnOs(OS.WINDOWS)
void testWindows() {
assertEquals("C:\\test.ini", config.getConfigFile("test.ini"));
}
@Test
@EnabledOnOs({OS.LINUX, OS.MAC})
void testLinuxAndMac() {
assertEquals("/usr/local/test.cfg", config.getConfigFile("test.cfg"));
}
@Test
@DisabledOnOs(OS.WINDOWS)
void testOnNonWindowsOs() {
// TODO: this test is disabled on windows
}
@Test
@DisabledOnJre(JRE.JAVA_8)
void testOnJava9OrAbove() {
// TODO: this test is disabled on java 8
}
@Test
@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")
void testOnlyOn64bitSystem() {
// TODO: this test is only run on 64 bit system
}
@Test
@EnabledIfEnvironmentVariable(named = "DEBUG", matches = "true")
void testOnlyOnDebugMode() {
// TODO: this test is only run on DEBUG=true
}
}
參數(shù)化測試
JUnit提供了一個@ParameterizedTest注解,用來進行參數(shù)化測試。參數(shù)化測試和普通測試稍微不同的地方在于,一個測試方法需要接收至少一個參數(shù),然后,傳入一組參數(shù)反復(fù)運行。
編寫一個方法,該方法把字符串的第一個字母變?yōu)榇髮?,后續(xù)字母變?yōu)樾憽?/p>
在編寫測試代碼的時候,需要給出輸入和預(yù)期輸出,可以通過@MethodSource注解,它允許我們編寫一個同名的靜態(tài)方法來提供測試參數(shù),編寫一個靜態(tài)方法testCapitalize返回了一組測試參數(shù),每個參數(shù)都包含兩個String,作為測試方法的兩個參數(shù)傳入。
還可以使用@CsvSource標(biāo)記傳入測試參數(shù)的方法,它的每一個字符串表示一行,一行包含的若干參數(shù)用 , 分隔。
如果測試數(shù)據(jù)很多,可以把測試數(shù)據(jù)提到一個獨立的CSV文件中,標(biāo)注上@CsvFileSource表示從CSV文件中讀取數(shù)據(jù)。
由于JUnit只在classpath中查找指定的CSV文件,因此,test-capitalize.csv這個文件要放到src/main/resources目錄下,內(nèi)容格式如下圖所示。
運行測試程序,測試結(jié)果如下圖所示。
?StringUtils.java文章來源:http://www.zghlxwxcb.cn/news/detail-769024.html
public class StringUtils {
public static String capitalize(String s) {
if (s.length() == 0) {
return s;
}
return Character.toUpperCase(s.charAt(0)) + s.substring(1).toLowerCase();
}
}
StringUtilsTest.java文章來源地址http://www.zghlxwxcb.cn/news/detail-769024.html
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;
import static org.junit.jupiter.api.Assertions.*;
public class StringUtilsTest {
// @ParameterizedTest
// @MethodSource
// void testCapitalize(String input, String result) {
// assertEquals(result, StringUtils.capitalize(input));
// }
//
// static List<Arguments> testCapitalize() {
// return List.of( // arguments:
// Arguments.of("abc", "Abc"), //
// Arguments.of("APPLE", "Apple"), //
// Arguments.of("gooD", "Good"));
// }
// @ParameterizedTest
// @CsvSource({"abc, Abc", "APPLE, Apple", "gooD, Good"})
// void testCapitalize(String input, String result) {
// assertEquals(result, StringUtils.capitalize(input));
// }
@ParameterizedTest
@CsvFileSource(resources = {"test_capitalize.csv"})
void testCapitalizeUsingCsvFile(String input, String result) {
assertEquals(result, StringUtils.capitalize(input));
}
}
到了這里,關(guān)于Java IDEA JUnit 單元測試的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!