不能为接口模拟(Mock IFeedResponse)传递构造函数参数



我正在尝试为DocumentDBRepository分页代码编写单元测试。由于FeedResponse中包含延续令牌,因此我需要模拟FeedResponse,以便为FeedResponse.ContinuationToken设置一些值。但问题是,我得到了一个错误说:

消息:System.ArgumentException:构造函数参数不能为通过接口模拟。

这是否意味着我无法模拟FeedResponse?或者我使用FeedResponse的方式可能是错误的?

这是我的代码:

var response = new Mock<IFeedResponse<T>>(expected);
response.Setup(_ => _.ResponseContinuation).Returns(It.IsAny<string>());
var mockDocumentQuery = new Mock<IFakeDocumentQuery<T>>();
mockDocumentQuery
.SetupSequence(_ => _.HasMoreResults)
.Returns(true)
.Returns(false);
mockDocumentQuery
.Setup(_ => _.ExecuteNextAsync<T>(It.IsAny<CancellationToken>()))
.Returns((Task<FeedResponse<T>>)response.Object);

当我调试时,断点停止在var response = new Mock<IFeedResponse<T>>(expected);,然后发生了错误。

错误是因为您正在模拟接口并试图传递构造函数参数。这不会像错误消息所说的那样工作。

但是,您可以使用FeedResponse的实际实例。

假设所需的成员不是virtual并且也是只读的,则可以考虑存根化该类并覆盖默认行为,因为FeedResponse<T>不是sealed

例如

public class FeedResponseStub<T> : FeedResponse<T> {
private string token;
public FeedResponseStub(IEnumerable<T> result, string token)
: base(result) {
this.token = token;
}
public new string ResponseContinuation {
get {
return token;
}
}
}

并在测试中使用存根

//...
var token = ".....";
var response = new FeedResponseStub<T>(expected, token);
//...
mockDocumentQuery
.Setup(_ => _.ExecuteNextAsync<T>(It.IsAny<CancellationToken>()))
.ReturnsAsync(response);
//...

以下是我在《宇航员》中处理它的方法。

public static FeedResponse<T> ToFeedResponse<T>(this IQueryable<T> resource, IDictionary<string, string> responseHeaders = null)
{
var feedResponseType = Type.GetType("Microsoft.Azure.Documents.Client.FeedResponse`1, Microsoft.Azure.DocumentDB.Core, Version=1.9.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
var headers = new NameValueCollection
{
{ "x-ms-request-charge", "0" },
{ "x-ms-activity-id", Guid.NewGuid().ToString() }
};
if (responseHeaders != null)
{
foreach (var responseHeader in responseHeaders)
{
headers[responseHeader.Key] = responseHeader.Value;
}
}
var arguments = new object[] { resource, resource.Count(), headers, false, null };
if (feedResponseType != null)
{
var t = feedResponseType.MakeGenericType(typeof(T));
var feedResponse = Activator.CreateInstance(t, flags, null, arguments, null);
return (FeedResponse<T>)feedResponse;
}
return new FeedResponse<T>();
}
}

您可以将延续令牌作为字典中的头键值传递,以设置FeedResponse值。您可以通过将x-ms-continuation值设置为令牌来完成此操作。

请记住,FeedResponseResponseContinuation属性也将useETagAsContinuation值考虑在内。在反射调用的构造函数中,我默认为false。

要获得任何进一步的参考,请检查项目的代码以及单元测试的编写方式。

最新更新