简体   繁体   English

使用Moq时在Dapper方法上获取NotSupportedException

[英]Getting NotSupportedException on Dapper method when using Moq

When using Moq I'm getting this exception below: 使用Moq我在下面得到此异常:

System.NotSupportedException: 'Expression references a method that does not belong to the mocked object: c => c.Query<MyClass>(It.IsAny<String>(), It.IsAny<Object>(), It.IsAny<IDbTransaction>(), It.IsAny<Boolean>(), It.IsAny<Nullable`1>(), (Nullable`1)It.IsAny<CommandType>())'

My class: 我的课:

public class MyClass
{
    public int Id {get; set;}
    public string Name {get; set;}
}

My actual BI class. 我实际的BI课。 I'm using Dapper for this class 我正在为这个课程使用Dapper

using Dapper;

//**
//**
//**
using (var con = _readRepository.CreateConnection())
{
    var query = "Select * FROM myTable"
    return con.Query<MyClass>(query, new { Skip = 0, Take = 10}, null, true, null, null);
}

My Unit Test: 我的单元测试:

var conMock = new Mock<IDbConnection>();

IEnumerable<MyClass> listModels = new List<MyClass>().AsEnumerable();

//The exception occurrs right here
conMock.Setup(c => c.Query<MyClass>(
        It.IsAny<string>(),
        It.IsAny<object>(),
        It.IsAny<IDbTransaction>(),
        It.IsAny<bool>(),
        It.IsAny<int?>(),
        It.IsAny<CommandType>()
))
.Returns(() => listModels);

//System.NotSupportedException: 'Expression references a method that does not belong to the mocked object: c => c.Query<MyClass>(It.IsAny<String>(), It.IsAny<Object>(), It.IsAny<IDbTransaction>(), It.IsAny<Boolean>(), It.IsAny<Nullable`1>(), (Nullable`1)It.IsAny<CommandType>())'

What I'm only trying to do is to mock Query<MyClass> method . 我只想做的是模拟Query<MyClass> 方法 What am I doing wrong? 我究竟做错了什么?

Query<T> is an extension method. Query<T>是扩展方法。

public static IEnumerable<T> Query<T>(
    this IDbConnection cnn, 
    string sql, 
    object param = null, 
    SqlTransaction transaction = null, 
    bool buffered = true
)

Moq however can't mock extension methods. Moq不能模拟扩展方法。 So either mock what is done internally in that extension method, which would involve having to go inspect the Dapper source code . 因此,要么模拟在该扩展方法内部进行的操作,要么必须检查Dapper源代码

or 要么

encapsulate that functionality behind an abstraction you control and can mock. 将该功能封装在您可以控制并可以模拟的抽象后面。

I tend to wrap external libraries with my own objects to make testing easy and language to taste. 我倾向于将外部库与自己的对象包装在一起,以使测试变得容易和易于使用。 Furthermore, you insulate potential changes in those libraries to the wrapping object. 此外,您可以将这些库中的潜在更改隔离到包装对象中。 Also, you can quickly add functionality such as caching to your methods. 另外,您可以快速将诸如缓存之类的功能添加到您的方法中。 But most importantly as it relates to this question, you can easily mock it. 但最重要的是,因为它与此问题相关,所以您可以轻松地模拟它。

public interface IDatabase{

IDbConnection GetConnection();
IEnumerable<T> Query<T>(whatever you want here...exactly Dapper's parameters if necessary);

}

public class Database : IDatabase{
     //implement GetConnection() however you like...open it too!
     public IEnumerable<T> Query<T>(...parameters...){

     IEnumerable<T> query = null;
     using(conn = this.GetConnection()){
          query = conn.Query<T>()//dapper's implementation
     }
     return query;
   }
}

Now you can mock your IDatabase with total control. 现在,您可以使用总控制来模拟IDatabase。

var mockDb = new Mock<IDatabase>();
mockDb.Setup(s=>s.Query(It.IsAny<>...whatever params...).Returns(...whatever you want to return...)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM