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

如何为返回Sealed类的方法编写单元测试并解决Mockito报错

如何为返回Sealed类Result的方法编写单元测试?

原Sealed类及扩展方法代码

sealed class Result<S, E extends Exception> {
  const Result();
}

final class Success<S, E extends Exception> extends Result<S, E> {
  const Success({required this.value});
  final S value;
}

final class Failure<S, E extends Exception> extends Result<S, E> {
  const Failure({required this.exception});
  final E exception;
}

extension ResultExtension on Result<dynamic, Exception> {
  dynamic get unwrap => switch (this) {
        Success() => (this as Success).value,
        Failure() => throw (this as Failure).exception,
      };
}

遇到的Mockito报错信息

MissingDummyValueError: Result<void, Exception>
  
This means Mockito was not smart enough to generate a dummy value of type
'Result<void, Exception>'. Please consider using either 'provideDummy' or 'provideDummyBuilder'
functions to give Mockito a proper dummy value.
  
Please note that due to implementation details Mockito sometimes needs users
to provide dummy values for some types, even if they plan to explicitly stub
all the called methods.

解决方案

1. 为Mockito注册Dummy值

Mockito无法自动生成自定义Sealed类的假值,需要手动注册。在测试文件的初始化阶段(比如main函数开头或setUp方法中)添加以下代码:

import 'package:mockito/mockito.dart';

void main() {
  // 注册Result<void, Exception>的默认假值
  provideDummy<Result<void, Exception>>(const Success<void, Exception>(value: null));
  
  // 或者使用Builder动态生成(适合需要不同假值的场景)
  // provideDummyBuilder<Result<void, Exception>>(() => const Success<void, Exception>(value: null));
  
  // 后续测试逻辑...
}

2. 对返回Result的方法进行Stub测试

假设你有一个被Mock的服务类,其中包含返回Result<void, Exception>的方法,示例测试代码如下:

import 'package:test/test.dart';
import 'package:mockito/mockito.dart';

// 定义被Mock的服务类
class MockService extends Mock implements Service {}

// 假设的Service接口
abstract class Service {
  Result<void, Exception> someMethod();
}

void main() {
  late MockService mockService;

  setUp(() {
    mockService = MockService();
    // 注册Dummy值
    provideDummy<Result<void, Exception>>(const Success<void, Exception>(value: null));
  });

  test('测试成功场景', () {
    // Stub成功返回值
    when(mockService.someMethod()).thenReturn(const Success<void, Exception>(value: null));
    
    // 执行方法并断言结果类型
    final result = mockService.someMethod();
    expect(result, isA<Success<void, Exception>>());
  });

  test('测试失败场景', () {
    final testException = Exception('测试错误');
    // Stub失败返回值
    when(mockService.someMethod()).thenReturn(Failure<void, Exception>(exception: testException));
    
    // 执行方法并断言结果
    final result = mockService.someMethod();
    expect(result, isA<Failure<void, Exception>>());
    expect((result as Failure).exception, testException);
  });
}

3. 优化Result扩展方法(可选)

原扩展方法使用dynamic不够类型安全,建议改成泛型版本,提升测试和业务代码的类型安全性:

extension ResultExtension<S, E extends Exception> on Result<S, E> {
  S get unwrap => switch (this) {
        Success(value: final v) => v,
        Failure(exception: final e) => throw e,
      };
}

对应的测试示例:

test('unwrap成功返回对应值', () {
  const success = Success(value: '测试内容');
  expect(success.unwrap, '测试内容');
});

test('unwrap失败抛出异常', () {
  final testException = Exception('错误信息');
  final failure = Failure(exception: testException);
  expect(() => failure.unwrap, throwsA(testException));
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 16:13:41