You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在单元测试中高效验证Controller兼容各Shape子类实例?

无冗余的Controller单元测试方案

核心思路:拆分两个独立测试维度

把测试拆成互不重叠的两部分,彻底避免场景与Shape类型的组合冗余:

  • 场景路径覆盖:聚焦Controller的校验逻辑和业务分支,用单个Shape实例(或Mock对象)覆盖所有成功、错误等场景——毕竟Controller的逻辑只依赖Shape接口,和具体子类无关。
  • Shape兼容性验证:单独验证所有6种Shape子类都能被Controller正确接收并传递给Service,无需重复场景逻辑。

具体实现(基于JUnit 5 + Mockito)

1. 场景路径覆盖测试

随便选一个具体Shape子类(比如Circle)或者Mock的Shape对象,就能覆盖doSomething的所有分支:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class ControllerScenarioTests {

    @Mock
    private Service mockService;

    @InjectMocks
    private Controller controller;

    // 测试校验成功的正常流程
    @Test
    void doSomething_ValidShape_CallsServiceSendData() {
        Shape validShape = new Circle();
        
        controller.doSomething(validShape);
        
        // 验证Service的sendData被正确调用
        verify(mockService).sendData(validShape);
    }

    // 测试空Shape触发的校验错误
    @Test
    void doSomething_NullShape_ThrowsValidationException() {
        org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> {
            controller.doSomething(null);
        });
        
        // 验证Service没被调用
        verify(mockService, never()).sendData(any(Shape.class));
    }

    // 测试不符合业务规则的错误分支(比如Shape属性不合法)
    @Test
    void doSomething_InvalidShape_ThrowsBusinessException() {
        // 用Mock模拟不符合校验的Shape
        Shape invalidShape = mock(Shape.class);
        // 如果校验依赖Shape的方法,可通过Mock返回非法值:
        // when(invalidShape.someValidationMethod()).thenReturn(false);
        
        org.junit.jupiter.api.Assertions.assertThrows(BusinessException.class, () -> {
            controller.doSomething(invalidShape);
        });
        
        verify(mockService, never()).sendData(invalidShape);
    }
}

2. Shape兼容性验证测试

用参数化测试遍历所有Shape子类,验证每个类型都能被正确处理:

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.stream.Stream;

import static org.mockito.Mockito.verify;

@ExtendWith(MockitoExtension.class)
class ControllerShapeCompatibilityTests {

    @Mock
    private Service mockService;

    @InjectMocks
    private Controller controller;

    // 提供所有Shape子类的实例
    private static Stream<Shape> allShapeInstances() {
        return Stream.of(
            new Circle(),
            new Square(),
            new Triangle(), // 假设存在的其他子类
            new Rectangle(),
            new Pentagon(),
            new Hexagon()
        );
    }

    // 参数化测试,逐个验证每个Shape类型
    @ParameterizedTest
    @MethodSource("allShapeInstances")
    void doSomething_AnyShapeType_CallsServiceSendData(Shape shape) {
        controller.doSomething(shape);
        
        // 验证每个Shape都能被正确传递给Service
        verify(mockService).sendData(shape);
    }
}

为什么这种方式无冗余?

  • 场景测试只关注Controller的逻辑分支,单个Shape就够覆盖所有路径,不用为每个Shape重复写场景用例。
  • 兼容性测试只关注类型适配,验证所有Shape都能被处理,不涉及场景分支,彻底避免了6×N的组合冗余。
  • 两个维度独立维护:新增场景只需要在场景测试里加用例,新增Shape子类只需要在allShapeInstances()里加实例。

内容的提问来源于stack exchange,提问作者Sankalp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 07:05:25