{C#-05A} 单测.替换
2020-09-09 本文已影响0人
码农猫爸
背景
- 单测本质:用已知(小环境),验未知(方法|属性)。
- 小环境在生产时是动态值,测试时需替换为模拟值(可多样本)。
注入法
- 可注入接口|类,因整体替换更简洁。
- A类调用B类,平行开发无B类时也能完成A类编写和单测。
- 生产代码与单测代码隔离。
内联法
- 可替换方法和属性,逐一替换显琐碎。
- 减少了接口|传参数量。
代码例(亲测有效)
- 注入法
using Moq;
using System;
using System.Diagnostics;
using Xunit;
namespace Injection
{
public interface IValidator
{
bool Validate();
}
public class Inner : IValidator // 被调用类
{
public bool Validate() => throw new NotImplementedException();
}
public class Outer // 调用类
{
private IValidator validator;
// 传参
public Outer(IValidator validator) => this.validator = validator;
public string GetMessage() => validator.Validate() ? "合法" : "非法";
}
public class Production // 生产环境
{
private Outer outer;
public Production() => outer = new Outer(new Inner());
public void Do() => Debug.Print(outer.GetMessage());
}
public class OuterTests // 单测环境
{
private Mock<IValidator> mock = new Mock<IValidator>();
private Outer outer;
[Theory(DisplayName = "演示")]
[InlineData(true, "合法")]
[InlineData(false, "非法")]
public void GetMessage_ReturnsTrue(bool valid, string expected)
{
mock
.Setup(x => x.Validate())
.Returns(valid);
outer = new Outer(mock.Object);
string actual = outer.GetMessage();
Assert.Equal(expected, actual);
}
}
}
- 内联法
using Moq;
using Moq.Protected;
using System;
using System.Diagnostics;
using Xunit;
namespace Inline
{
public class Inner // 被调用类
{
public bool Validate() => throw new NotImplementedException();
}
public class Outer // 调用类
{
private Inner inner = new Inner(); // 内联,不传参
public string GetMessage() => Validate() ? "合法" : "非法";
protected virtual bool Validate() => inner.Validate();
}
public class Production // 生产环境
{
private Outer outer;
public Production() => outer = new Outer();
public void Do() => Debug.Print(outer.GetMessage());
}
public class OuterTests // 单测环境
{
private Mock<Outer> mock = new Mock<Outer>();
[Theory(DisplayName = "演示")]
[InlineData(true, "合法")]
[InlineData(false, "非法")]
public void GetMessage_ReturnsTrue(bool valid, string expected)
{
mock.Protected()
.Setup<bool>("Validate")
.Returns(valid);
string actual = mock.Object.GetMessage();
Assert.Equal(expected, actual);
}
}
}