隔离框架1-介绍和使用

代码地址:http://git.oschina.net/zhv/UnitTest

隔离框架介绍

使用隔离框架的好处

  • 可以把开发人员从编写重复代码,进行断言或模拟对象交互中解放出来
  • 对于手工编写伪对象实现复杂接口时,不仅花费时间长,写起来还费劲

使用隔离框架的好处

  • 动态伪对象就是在运行时创建的任何存根(桩)或者模拟对象。
  • 使用动态伪对象,就不用手工编写代码实现接口或者派生类了。

用动态伪对象替换手工伪对象

被测类

public class LogAnalyzer
{
    private ILogger _logger;

    public LogAnalyzer(ILogger logger)
    {
        _logger = logger;
    }

    public int MinNameLength { get; set; }

    public void Analyze(string filename)
    {
        if (filename.Length<MinNameLength)
        {
            _logger.LogError(string.Format("Filename too short: {0}",filename));
        }
    }
}

public interface IFileNameRules
{
    bool IsValidLogFileName(string fileName);
}
public interface ILogger
{
    void LogError(string message);
}
public interface IWebService
{
    void Write(string message);
    void Write(ErrorInfo message);
}

手工伪对象测试

//使用手工伪对象进行测试
[Test]
public void Analyze_TooShortFileName_CallLogger()
{
    //下面这句后面会被隔离框架替换掉
    FakeLogger logger=new FakeLogger();

    LogAnalyzer analyzer=new LogAnalyzer(logger);
    analyzer.MinNameLength = 6;
    analyzer.Analyze("a.txt");

    //下面这句后面会被隔离框架替换掉
    StringAssert.Contains("too short", logger.LastError);
}

class FakeLogger : ILogger
{
    public string LastError;

    public void LogError(string message)
    {
        LastError = message;
    }
}

使用NSubstitute伪造对象

//使用NSubstitute生成的动态伪对象来测试
[Test]
public void Analyze_TooShortFileName_UseNSub_CallLogger()
{
    ILogger logger = Substitute.For<ILogger>();
    LogAnalyzer analyzer=new LogAnalyzer(logger);
    analyzer.MinNameLength = 6;
    analyzer.Analyze("a.txt");
    //使用NSub的API设置预期字符串,Received()这个方法在什么对象上调用,就会返回和这个对象同样类型的对象,但实际上是在声明断言对象。
    //如果不加Received(),伪对象就会认为这个调用是产品代码发出的。
    //使用Received(),就是在询问它后面的这个LogError是否调用过。
    logger.Received().LogError("Filename too short: a.txt");
}

使用隔离框架也是符合“准备-执行-断言”这个结构要求

  • 首先准备伪对象,然后执行要测试的功能,最后在测试结尾进行断言
  • 使用准备-执行-断言模式编写的测试代码具有良好的可读性。

使用隔离框架创建模拟对象和桩

从伪对象返回一个值(模拟值)

//模拟值:使用动态伪对象生成一个桩,提供被测试系统需要的值
[Test]
public void Returns_ByDefault_WorksForHardCodedArgument()
{
    IFileNameRules fakeRules = Substitute.For<IFileNameRules>();

    //强制方法调用时返回一个假值
    fakeRules.IsValidLogFileName("strict.txt").Returns(true);

    //因为调用了“fakeRules.IsValidLogFileName("strict.txt")”所以根据框架设置,返回了true
    Assert.IsTrue(fakeRules.IsValidLogFileName("strict.txt"));
}

使用参数匹配器(argument matcher)

使用参数匹配器就可以无论参数是什么,方法总是返回一个假值,这样维护起来会非常容易。

//使用参数匹配器:不用管参数是什么,方法都返回一个假值
[Test]
public void Returns_ByDefault_WorksForHardCodedArgument2()
{
    IFileNameRules fakeRules = Substitute.For<IFileNameRules>();

    //这个Arg.Any<string>()就是参数匹配器,只要是string都会返回一个假值(例子里是true)
    fakeRules.IsValidLogFileName(Arg.Any<string>()).Returns(true);

    Assert.IsTrue(fakeRules.IsValidLogFileName("anything.txt"));
}

使用隔离框架模拟异常

//使用NSub模拟异常
[Test]
public void Returns_ArgAny_Throws()
{
    IFileNameRules fakeRules = Substitute.For<IFileNameRules>();

    //When方法必须使用Lambda表达式,其中x代表要改变行为的伪对象,context包含调用的参数值
    fakeRules.When(x => x.IsValidLogFileName(Arg.Any<string>()))
        .Do(context=>{throw new Exception("fake exception");});

    Assert.Throws<Exception>(()=>fakeRules.IsValidLogFileName("anything"));
}

转载于:https://my.oschina.net/zhv/blog/908539

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值