VS2012 Unit Test——Microsoft Fakes入门

转载地址:

http://www.cnblogs.com/FreeDong/p/3353111.html

http://msdn.microsoft.com/zh-cn/library/hh708916

如题,本文主要作为在VS2012使用Fakes的入门示例,开发工具必须是VS2012或更高版本。

关于Fakes的MSDN地址:http://msdn.microsoft.com/en-us/library/hh549175.aspx

关于VS2012单元测试的前期文章:

1.《在Visual Studio 2012使用单元测试》、

2.《VS2012 单元测试之泛型类(Generics Unit Test)》、

3.《VS2012 Unit Test —— 我对接口进行单元测试使用的技巧

4.《VS2012 Unit Test(Void, Action, Func) —— 对无返回值、使用Action或Func作为参数、多重载的方法进行单元测试

 

依我个人理解单元测试就是对程序的小单元进行测试,一个测试不应包含两个或更多单元,总体而言大多都是对方法、属性的编码正确性进行验证。但是往往一个方法又会调用其他的方法或属性,我这里暂称之为外部依赖,因而外部依赖会影响程序单元的测试结果,要避免这样的情况就不得不使用一些外部依赖的模拟进行隔离(Isolate),本文就是使用了Microsoft Fakes,当然还有其他更为流行的框架可以选择使用(Moq、Rhino Mocks、Type Mock)

 

Fakes有两种形式:stub 和 shim。具体的介绍我就不啰嗦,因为我英文不好可能会表达错误误导新人。

我的Demo也是看了MSDN后以个人理解后进行简单的编写,如果MSDN看懂了也就不用看以下内容了,期待和我一样正在使用VS2012 MSTest进行单元测试的一起交流进步。

 

一、shim

以下将模拟DateTime的Now属性,假设我现在需要在活动服务类ActivityService添加一个方法验证某个线下活动是否过期。

1. 打开VS2012,创建单元测试项目FakesTesting,我这是测试先行。重命名项目自动生成的类UnitTest1为ActivityServiceTest,将TestMethod1改为IsExpireTest(是否过期).

2. 添加代码“ActivityService service = new ActivityService();”并使用VS快捷功能为我们创建ActivityService 类

3. 添加Fakes,由于DateTime位于System程序集,因而将添加System的Fake程序集(右键System程序集),  然后在测试类“using System.Fakes;”

4.  编写测试代码如下

复制代码
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Fakes;
using Microsoft.QualityTools.Testing.Fakes;

namespace FakesTesting.Test
{
    [TestClass]
    public class ActivityServiceTest
    {
        [TestMethod]
        public void IsExpireTest()
        {
            ActivityService service = new ActivityService();
            bool actual = service.IsExpire();
            Assert.IsFalse(actual);

            using (ShimsContext.Create())
            {
                ShimDateTime.NowGet = () => new DateTime(2014, 5, 5);
                actual = service.IsExpire();
                Assert.IsFalse(actual);
            }
        }
    }
}
复制代码

5. 然后编写ActivityService类

复制代码
    public class ActivityService
    {
        public DateTime BeginTime { get; set; }

        public ActivityService()
        {
            this.BeginTime = new DateTime(2014, 3, 3);  //仅作演示,无意义
        }

        public bool IsExpire()
        {
            return BeginTime >= DateTime.Now;
        }
    }
复制代码

6. 运行测试通过。然后就可以把实际业务类移动到相应VS项目中,并调整命名空间。

 

二、Stub

现在假设ActivityService类有一个方法获取是否还能报名,但是它依赖于仓储IActivityRepository(只有遵循依赖反转与接口隔离原则的代码才好使用Stub填充外部依赖)提供的RegisterNumber方法。

1. IActivityRepository接口(新建IRepositories项目并添加该接口)

复制代码
    public interface IActivityRepository
    {
        /// <summary>
        /// 已报名人数
        /// </summary>
        int RegisterNumber();
    }
复制代码

2. 而我们的单元测试现在不能依赖具体(实际环境中的Repository可能对测试带来影响),这时候就能使用Stub来填充该接口了,添加IRepositories引用,然后与上一个Demo一样的添加IRepositories的Fakes程序集。

3. 在测试类中添加Using代码

using IRepositories;
using IRepositories.Fakes;

4. 编写测试代码

复制代码
        [TestMethod]
        public void CanRegisterTest()
        {
            StubIActivityRepository repository = new StubIActivityRepository();
            ActivityService service = new ActivityService(repository);

            //如果已报名人数小于最多可报名数量则不能再报名,断言CanRegister方法应为True
            repository.RegisterNumber = ()=> 20;
            bool actual = service.CanRegister();
            Assert.IsTrue(actual);

            //如果已报名人数大于等于最多可报名数量则不能再报名,断言CanRegister方法应为False
            repository.RegisterNumber = () => 50;
            actual = service.CanRegister();

        Assert.IsFalse(actual);
      }

 
 
复制代码

5. ActivityService代码:

复制代码
    public class ActivityService
    {
        public DateTime BeginTime { get; set; }

        /// <summary>
        /// 最多可报名数量
        /// </summary>
        private int maxCount = 50;
        private IActivityRepository repository;

        public ActivityService()
        {
            this.BeginTime = new DateTime(2014, 3, 3);  //仅作演示,无意义
        }

        public ActivityService(IActivityRepository repository)
        {
            // TODO: Complete member initialization
            this.repository = repository;
        }
        
        public bool IsExpire()
        {
            return BeginTime >= DateTime.Now;
        }

        public bool CanRegister()
        {
            return repository.RegisterNumber() < this.maxCount;
        }
    }
复制代码

 

总结

stub用于我们可控的代码,shim用于不可控的,例如.NET Framework以及第三方类库等。

备注:

fakes


  • n. 赝品;云母板状岩;假冒商品(fake的复数)
  • v. 佯装;假装(fake的三单形式)
  • n. (Fakes)人名;(法)法克

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值