【软件测试】JUnit单元测试实战:从BMI计算器到企业级测试策略

1. JUnit单元测试基础与BMI计算器实战

第一次接触JUnit时,我盯着那些@Test注解发懵——直到把BMI计算器的算法拆解成测试用例才恍然大悟。单元测试就像给代码做"体检",而JUnit就是最趁手的检查仪器。先看这个简单的BMI分类逻辑:

public String getBMIType() { if(bmi<18.5) return "偏瘦"; else if(bmi<24) return "正常"; else if(bmi<28) return "偏胖"; else return "肥胖"; }

1.1 测试环境搭建的坑与经验

在Eclipse里新建JUnit测试类时,我遇到过两个典型问题:

  1. 忘记添加JUnit库依赖,导致@Test注解报红
  2. 测试类和方法没有用public修饰,运行按钮是灰色的

正确姿势是用Maven管理依赖:

<dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.8.2</version> <scope>test</scope> </dependency>

1.2 第一个有效测试用例

给"偏瘦"分类写测试时,我最初直接写死了身高体重:

@Test void testThin() { BMI bmi = new BMI(45, 1.6); assertEquals("偏瘦", bmi.getBMIType()); }

后来发现更好的做法是用边界值:

@Test void testThinBoundary() { // 18.5的边界值:1.6m身高对应47.36kg BMI bmi = new BMI(47.35, 1.6); assertEquals("偏瘦", bmi.getBMIType()); }

2. 企业级测试策略设计

在电商项目踩过坑后,我总结出测试用例设计的"三明治法则":

2.1 黑盒测试方法实战

等价类划分示例(BMI场景):

分类输入范围有效等价类无效等价类
偏瘦<18.517.5-1
正常18.5~24200
偏胖24~2826身高为负数

边界值分析的经典场景:

@ParameterizedTest @ValueSource(doubles = {17.9, 18.4, 18.5, 23.9, 24.0, 27.9, 28.0}) void testBoundaries(double bmiValue) { BMI bmi = new BMI(); bmi.setBMI(bmiValue); assertNotNull(bmi.getBMIType()); }

2.2 测试生命周期管理

在物流系统中,我用@BeforeEach初始化运单号生成器:

class WaybillTest { private WaybillGenerator generator; @BeforeEach void init() { generator = new WaybillGenerator(); generator.setPrefix("SF"); } @Test void generateId() { String id = generator.generate(); assertTrue(id.startsWith("SF2023")); } }

3. 高级测试技巧与异常处理

支付模块的测试让我深刻认识到异常处理的重要性...

3.1 参数化测试进阶

用CSV文件管理测试数据:

@ParameterizedTest @CsvFileSource(resources = "/bmi_testcases.csv") void testWithCsv(double weight, double height, String expected) { BMI bmi = new BMI(weight, height); assertEquals(expected, bmi.getBMIType()); }

bmi_testcases.csv示例:

45,1.6,偏瘦 55,1.6,正常 68,1.6,偏胖 80,1.6,肥胖 0,1.6,无效输入

3.2 超时与并发测试

测试缓存服务时这样验证性能:

@Test @Timeout(5) void cacheResponseUnderLoad() throws Exception { ExecutorService pool = Executors.newFixedThreadPool(10); for(int i=0; i<100; i++) { pool.submit(() -> { assertNotNull(cache.get("key")); }); } pool.shutdown(); assertTrue(pool.awaitTermination(10, SECONDS)); }

4. 企业级集成实践

在CI流水线中,我们这样配置Maven插件:

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.0.0</version> <configuration> <includes> <include>**/*Test.java</include> </includes> <excludes> <exclude>**/StressTest.java</exclude> </excludes> </configuration> </plugin>

4.1 测试报告优化

使用Allure生成可视化报告:

<dependency> <groupId>io.qameta.allure</groupId> <artifactId>allure-junit5</artifactId> <version>2.13.0</version> </dependency>

关键注解示例:

@Epic("健康管理") @Feature("BMI计算") @Story("用户BMI分类") @Test void shouldReturnObeseWhenBMIOver28() { // ... }

4.2 测试覆盖率控制

JaCoCo配置阈值示例:

<plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.7</version> <executions> <execution> <goals> <goal>prepare-agent</goal> </goals> </execution> <execution> <id>check-coverage</id> <goals> <goal>check</goal> </goals> <configuration> <rules> <rule> <limit> <counter>LINE</counter> <value>COVEREDRATIO</value> <minimum>0.8</minimum> </limit> </rule> </rules> </configuration> </execution> </executions> </plugin>