首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用Moq来模拟具有以具体类为参数的方法的接口?

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

Stack Overflow用户
提问于 2016-08-16 18:32:13
回答 2查看 667关注 0票数 0
  1. 我有这样的场景:一个有两个方法的接口
  2. 这两个方法接受请求并返回响应。
  3. 方法包含内部功能(检查权限和验证请求,并使用实体框架从数据库中获取数据)。
  4. 但是我想测试这些方法,而不仅仅是接口。
  5. 我已经成功地测试了接口,但是现在我想输入方法并在其中进行测试。

代码示例:

代码语言:javascript
复制
 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
          }
       }
    }

现在,我想测试检查空、权限和数据访问,可以吗?还是必须从内部方法中提取接口?

这是给我的单元测试用的。我试图消除外部依赖。请详细解释

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-08-16 18:37:16

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

在这种情况下,请考虑创建新代码所在的一个或多个新类。这样,您就可以通过公共方法对代码进行单元测试。另外的好处是您的代码在单一责任原则。方面可能更好。

票数 1
EN

Stack Overflow用户

发布于 2016-08-16 22:06:59

嘲笑的原因是为了让您能够控制行为;在这种情况下,我将冒险猜测Service<RequestObject>实际上没有任何行为,因此它实际上不需要被嘲笑。所以它很可能会像在任何测试中一样通过。

但是,如果它确实具有行为,并且该行为跨越了体系结构边界(例如在GetData方法中,您正在调用request参数上的某个方法,该方法将进行网络调用或访问文件系统等等)。那你就得嘲笑它了。但你可以很容易地做到:

代码语言:javascript
复制
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方法。此外,您还可以根据需要在接口上模拟任何方法。显然,如果您不控制调用代码,这是个问题,因为编写代码的人需要这样做,但这是您需要与他们进行的对话:)

在测试内部操作方面,您需要研究如何抽象GetData方法使用的任何依赖行为--例如,contextEntityCheckForNullValidateMethod等--所有这些都是要提取到自己的抽象中的候选项,并将注射作为依赖项提取到MyConcreteClass中,例如:

代码语言:javascript
复制
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;
   }
}

现在您可以为MyConcreteClass编写测试并使用模拟的依赖项实现,以确保GetData方法正确地使用它们。

**我猜这可以用一个简单的if request==null throw new ArgumentNullException()来代替,因为它更干净,也更简单。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38982105

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档