如何对含私有集合循环获取方法的类进行单元测试?
单元测试方案咨询
问题代码片段
public class vm : IViewModel { private readonly List<Brush> _brushes; private int _brushIndex; private readonly IModelCollection _modelCollection; private SomeModel _model; // 假设存在该字段 public vm(IModelCollection modelCollection) { _modelCollection = modelCollection; _brushes = new List<Brush> { Brushes.Red, Brushes.Blue, Brushes.Green }; } public void AddSig(ISigModel sigModel) { _model.Brush = GetNextBrush(); if (sigModel.IsAtt) { sigModel.Process = "StartEvent"; } _modelCollection.AddSig(sigModel); StartCSUpdatingEvent(); } private Brush GetNextBrush() { var brush = _brushes[_brushIndex]; _brushIndex++; if (_brushIndex == _brushes.Count) { _brushIndex = 0; } return brush; } }
核心疑问
我通过构造函数初始化私有画笔集合,用私有方法GetNextBrush循环返回画笔供公开方法AddSig使用。现在想对这部分逻辑做单元测试,但不想把私有方法设为公开,也不确定是否需要将集合提取为带接口的服务注入构造函数(感觉有点小题大做),请问恰当的测试方式是什么?
测试方案建议
1. 聚焦公开行为测试(优先选择)
单元测试的核心是验证类的对外契约,而非内部私有实现。你可以通过多次调用公开方法AddSig,验证以下核心逻辑:
- 每次调用后,
_model.Brush的取值顺序是否符合预期:红→蓝→绿→红→蓝...循环往复 - 覆盖
AddSig的其他分支:比如当sigModel.IsAtt为true时,sigModel.Process是否被设为"StartEvent";_modelCollection.AddSig是否被正确调用;StartCSUpdatingEvent是否触发等
这种方式无需修改原有代码,直接针对公开行为测试,就能完全覆盖GetNextBrush的循环逻辑。
2. 可选:注入画笔集合提升测试灵活性
如果需要在测试中自定义画笔集合(比如用更少的元素验证循环逻辑,或者测试边界场景),可以给构造函数添加可选的集合参数,无需引入复杂接口:
修改构造函数:
public vm(IModelCollection modelCollection, IReadOnlyList<Brush> brushes = null) { _modelCollection = modelCollection; // 生产环境使用默认集合,测试时可传入自定义集合 _brushes = brushes ?? new List<Brush> { Brushes.Red, Brushes.Blue, Brushes.Green }; }
测试示例:
// 测试用自定义集合 var testBrushes = new List<Brush> { Brushes.Yellow, Brushes.Black }; var viewModel = new vm(mockModelCollection.Object, testBrushes); // 调用三次AddSig,验证画笔循环逻辑 viewModel.AddSig(mockSigModel1.Object); Assert.Equal(Brushes.Yellow, viewModel._model.Brush); viewModel.AddSig(mockSigModel2.Object); Assert.Equal(Brushes.Black, viewModel._model.Brush); viewModel.AddSig(mockSigModel3.Object); Assert.Equal(Brushes.Yellow, viewModel._model.Brush);
这种方式既保持了生产代码的简洁,又给测试提供了灵活性,比提取接口服务更轻量。
3. 避免过度设计
如果当前画笔集合是固定不变的,且通过公开行为测试已经能完全覆盖逻辑,就没必要将集合提取为带接口的服务。过度设计会增加代码复杂度,反而得不偿失。
内容的提问来源于stack exchange,提问作者Blingers
相关产品推荐
相关产品推荐

