如何为JPhotoFrame编写JUnit测试?价格计算逻辑测试指导
第一步:重构代码,分离业务逻辑
原代码把UI和费用计算逻辑耦合在itemStateChanged方法里,直接测试UI组件会很麻烦。先把计算逻辑抽成独立类,方便后续单元测试:
package PhotoFrame; public class PortraitCalculator { public static final double LOC_PRICE = 90.00; public static final double STUDIO_PRICE = 40.00; public static final double ONE_HUMAN_SUBJECT_PRICE = 40.00; public static final double MORE_HUMAN_SUBJECTS_PRICE = 75.00; public static final double PET_SUBJECT_PRICE = 95.00; public static double calculateTotal(boolean isStudioSelected, boolean isLocationSelected, boolean isOneHumanSelected, boolean isMoreHumansSelected, boolean isPetSelected) { double total = 0.0; // 处理拍摄地点(二选一) if (isStudioSelected) { total += STUDIO_PRICE; } else if (isLocationSelected) { total += LOC_PRICE; } // 处理拍摄主体(可多选) if (isOneHumanSelected) { total += ONE_HUMAN_SUBJECT_PRICE; } if (isMoreHumansSelected) { total += MORE_HUMAN_SUBJECTS_PRICE; } if (isPetSelected) { total += PET_SUBJECT_PRICE; } return total; } }
然后修改原JPhotoFrame的itemStateChanged方法,调用这个计算器:
@Override public void itemStateChanged(ItemEvent check) { double total = PortraitCalculator.calculateTotal( studioBox.isSelected(), locBox.isSelected(), oneBox.isSelected(), moreBox.isSelected(), petBox.isSelected() ); totPrice.setText(String.format("%.2f", total)); }
第二步:编写JUnit测试用例
以JUnit 5为例,编写测试类覆盖所有核心场景,常用的Assert语句说明:
Assert.assertEquals:验证计算结果是否符合预期(浮点数需指定误差范围)- 若需验证布尔逻辑,可使用
Assert.assertTrue/Assert.assertFalse,这里核心用assertEquals
测试代码示例:
package PhotoFrame; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; public class PortraitCalculatorTest { // 仅选Studio @Test void testOnlyStudio() { double total = PortraitCalculator.calculateTotal(true, false, false, false, false); assertEquals(40.00, total, 0.001); // 第三个参数是允许的误差,避免浮点数精度问题 } // 仅选On Location @Test void testOnlyLocation() { double total = PortraitCalculator.calculateTotal(false, true, false, false, false); assertEquals(90.00, total, 0.001); } // Studio + 1个人类主体 @Test void testStudioAndOneHuman() { double total = PortraitCalculator.calculateTotal(true, false, true, false, false); assertEquals(80.00, total, 0.001); } // Location + 多人类主体 + 宠物 @Test void testLocationMoreHumansAndPet() { double total = PortraitCalculator.calculateTotal(false, true, false, true, true); assertEquals(260.00, total, 0.001); } // 未勾选任何选项 @Test void testNoOptions() { double total = PortraitCalculator.calculateTotal(false, false, false, false, false); assertEquals(0.00, total, 0.001); } // 同时选Studio和Location(UI中ButtonGroup会限制,但测试逻辑分支) @Test void testStudioAndLocationBothSelected() { double total = PortraitCalculator.calculateTotal(true, true, false, false, false); assertEquals(40.00, total, 0.001); // 逻辑优先Studio } }
第三步:UI交互测试(可选)
如果需要验证UI组件的交互逻辑,可使用AssertJ Swing库,示例:
package PhotoFrame; import org.assertj.swing.edt.GuiActionRunner; import org.assertj.swing.fixture.FrameFixture; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class JPhotoFrameUITest { private FrameFixture window; @BeforeEach void setUp() { JPhotoFrame frame = GuiActionRunner.execute(JPhotoFrame::new); window = new FrameFixture(frame); window.show(); } @Test void testStudioAndPetSelection() { window.checkBox("In studio").check(); window.checkBox("Pet subject ").check(); window.textBox().requireText("135.00"); } @AfterEach void tearDown() { window.cleanUp(); } }
关键注意事项
- 浮点数测试必须指定误差范围,避免因精度问题导致测试失败
- 优先测试独立业务逻辑,比直接测试UI更稳定、高效
- 覆盖所有边界场景:空选择、互斥选项、多选组合等
内容的提问来源于stack exchange,提问作者Amiibo
相关产品推荐
相关产品推荐

