如何使用Moq来模拟具有将具体类作为参数的方法的接口?

时间:2016-08-16 18:32:14

标签: c# unit-testing testing moq

  1. 我有这种情况:一个包含2个方法的界面
  2. 这两种方法接受请求并返回响应
  3. 方法包含内部功能(检查权限和验证请求,并使用实体框架从数据库获取数据。
  4. 但我想测试方法,而不仅仅是界面。
  5. 我已成功测试了界面,但现在我想进入方法并在其中进行测试。
  6. 代码示例:

     public interface IMyInterface
        {
          [OperationContract]
          responseObject GetData(Service<RequestObject> request);
        }
    
        public class MyConcreteClass : IMyInterface
        {
           public responseObject GetData(Service<RequestObject> request)
           {
              CheckForNull(request);
              ValidateMethod(request);
              //connect to db
              using(var context = new contextEntity)
              {
                //get data
              }
           }
        }
    

    现在,我想测试检查空值,权限和数据访问,是否可能?或者我是否必须从内部方法中提取接口?

    PS,这是我的单元测试。我正在尝试消除外部依赖。 请详细说明

2 个答案:

答案 0 :(得分:1)

不应直接通过公共方法间接地直接对单元测试私有方法进行测试。如果您认为测试公共方法不够精确,那么方法和类可能已经太复杂了。

在这种情况下,请考虑创建一个或多个新代码所在的新类。这样您就可以通过公共方法对代码进行单元测试。额外的好处是您的代码在Single responsibility principle.

方面可能更好

答案 1 :(得分:0)

模仿的原因是你可以控制行为;在这种情况下,我会想出Service<RequestObject>实际上没有任何行为,因此它实际上并不需要被嘲笑。所以它可能只是在任何测试中按原样传递。

但是,如果确实有行为,并且该行为跨越架构边界(让我们在GetData方法中说你在{{1}上调用了一些方法将进行网络调用或访问文件系统等的参数,然后你需要模拟它。但你可以很容易地做到这一点:

request

然后更改public interface IService<RequestObject> { //put method and property signatures of Service<RequestObject> here } public class ServiceObject:Service<RequestObject>, IService<RequestObject> { public ServiceObject(RequestObject request): base(request){ //or however the Service<Request> object is instantiated. }; } 以获取GetData;现在,您的调用代码可以实例化IService<RequestObject>来代替服务,并将其传递给ServiceObject方法。另外,您可以根据需要在界面上模拟任何方法。显然,如果你不控制调用代码,这就是一个问题,因为无论谁编写代码都需要这样做,但这是你需要与他们进行的对话:)

在测试内部操作方面,您需要了解如何抽象GetData方法使用的任何依赖行为 - 例如GetDatacontextEntityCheckForNull等等 - 所有这些都被提取到他们自己的抽象中,injected被提取到ValidateMethod作为依赖,例如:

MyConcreteClass

现在您可以编写public class MyConcreteClass: IMyInterface { readonly INullChecker _nullChecker; readonly IValidator _validator; readonly IContextEntity _context; public MyConcreteClass(INullChecker nullChecker, IValidator validator, IContextEntity _context) { _nullChecker = nullChecker; _validator = validator; _context=context; } public responseObject GetData(Service<RequestObject> request) { _nullChecker.Check(request)//**; _validator.Validate(request); var result = _context.DoSomethingWith(request); return result; } } 的测试并使用依赖项的模拟实现,以确保GetData方法正确使用它们。

**我猜这可以用简单的MyConcreteClass代替,无论如何都更简洁。