无法使用 StackExchange.Redis 返回 RedisResult 的方法对 class 进行单元测试
Cannot unit test a class with a method returning RedisResult with StackExchange.Redis
我有一个用于 stackexchange redis 的简单包装器:
public interface IRedisClient
{
Task<RedisResult> ScriptEvaluate(LuaScript script, object parameters);
}
我有一个调用 ScriptEvaluate
的方法
public class Foo
{
private readonly IRedisClient _client;
public Foo(IRedisClient client)
{
_client = client;
}
public void RunScript()
{
_client.ScriptEvaluate(LuaScript.Prepare(""), new object());
}
}
现在,当我使用 NSubstitute
模拟注入到 Foo
的 IRedisClient
,然后调用 RunScript
public void Test()
{
_foo = new Foo(Substitute.For<IRedisClient>());
_foo.RunScript();
}
我收到以下错误:
System.TypeLoadException: Method 'AsBoolean' in type
'Castle.Proxies.RedisResultProxy' from assembly
'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=a621a9e7e5c32e69' does not have an implementation.
据我所知,Nsubstitute
/Castle
内部构件无法正确使用 RedisResult
。我没有找到任何解决方法。
可以用这个做点什么吗?
P.S。当我尝试将模拟配置为 return 一个值(相同的异常)时出现相同的错误:
_client
.ScriptEvaluate(null, null)
.ReturnsForAnyArgs(RedisResult.Create((RedisKey)"result"));
RedisResult
是一个abstract
类型,但是有static Create
个通用场景的方法,还有一些静态属性比如EmptyArray
,NullArray
等。我无法告诉您如何配置您的特定伪造层,但最终,我希望涉及 RedisResult.Create
我很好奇为什么模拟抽象 RedisResult
不是一个简单的解决方案。
这似乎是 NSubstitute 实施的问题。
使用以下方法尝试重现问题
public class Foo {
private readonly IRedisClient _client;
public Foo(IRedisClient client) {
_client = client;
}
public Task<RedisResult> RunScript() {
return _client.ScriptEvaluate(LuaScript.Prepare(""), new object());
}
}
我能够使用 NSubstitute
重现它,但在使用另一个模拟框架 (MOQ) 时能够完成测试
[TestClass]
public class MyTestClass {
[TestMethod]
public async Task Test1() {
//Arrange
var expected = RedisResult.Create((RedisKey)"result");
var _client = Substitute.For<IRedisClient>();
_client
.ScriptEvaluate(Arg.Any<LuaScript>(), Arg.Any<object>())
.Returns(expected);
var _foo = new Foo(_client);
//Act
var actual = await _foo.RunScript();
//Assert
actual.Should().Be(expected);
}
[TestMethod]
public async Task Test2() {
//Arrange
var expected = RedisResult.Create((RedisKey)"result");
var _client = Mock.Of<IRedisClient>(_ => _.ScriptEvaluate(It.IsAny<LuaScript>(), It.IsAny<object>()) == Task.FromResult(expected));
var _foo = new Foo(_client);
//Act
var actual = await _foo.RunScript();
//Assert
actual.Should().Be(expected);
}
}
我有一个用于 stackexchange redis 的简单包装器:
public interface IRedisClient
{
Task<RedisResult> ScriptEvaluate(LuaScript script, object parameters);
}
我有一个调用 ScriptEvaluate
public class Foo
{
private readonly IRedisClient _client;
public Foo(IRedisClient client)
{
_client = client;
}
public void RunScript()
{
_client.ScriptEvaluate(LuaScript.Prepare(""), new object());
}
}
现在,当我使用 NSubstitute
模拟注入到 Foo
的 IRedisClient
,然后调用 RunScript
public void Test()
{
_foo = new Foo(Substitute.For<IRedisClient>());
_foo.RunScript();
}
我收到以下错误:
System.TypeLoadException: Method 'AsBoolean' in type 'Castle.Proxies.RedisResultProxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=a621a9e7e5c32e69' does not have an implementation.
据我所知,Nsubstitute
/Castle
内部构件无法正确使用 RedisResult
。我没有找到任何解决方法。
可以用这个做点什么吗?
P.S。当我尝试将模拟配置为 return 一个值(相同的异常)时出现相同的错误:
_client
.ScriptEvaluate(null, null)
.ReturnsForAnyArgs(RedisResult.Create((RedisKey)"result"));
RedisResult
是一个abstract
类型,但是有static Create
个通用场景的方法,还有一些静态属性比如EmptyArray
,NullArray
等。我无法告诉您如何配置您的特定伪造层,但最终,我希望涉及 RedisResult.Create
我很好奇为什么模拟抽象 RedisResult
不是一个简单的解决方案。
这似乎是 NSubstitute 实施的问题。
使用以下方法尝试重现问题
public class Foo {
private readonly IRedisClient _client;
public Foo(IRedisClient client) {
_client = client;
}
public Task<RedisResult> RunScript() {
return _client.ScriptEvaluate(LuaScript.Prepare(""), new object());
}
}
我能够使用 NSubstitute
重现它,但在使用另一个模拟框架 (MOQ) 时能够完成测试
[TestClass]
public class MyTestClass {
[TestMethod]
public async Task Test1() {
//Arrange
var expected = RedisResult.Create((RedisKey)"result");
var _client = Substitute.For<IRedisClient>();
_client
.ScriptEvaluate(Arg.Any<LuaScript>(), Arg.Any<object>())
.Returns(expected);
var _foo = new Foo(_client);
//Act
var actual = await _foo.RunScript();
//Assert
actual.Should().Be(expected);
}
[TestMethod]
public async Task Test2() {
//Arrange
var expected = RedisResult.Create((RedisKey)"result");
var _client = Mock.Of<IRedisClient>(_ => _.ScriptEvaluate(It.IsAny<LuaScript>(), It.IsAny<object>()) == Task.FromResult(expected));
var _foo = new Foo(_client);
//Act
var actual = await _foo.RunScript();
//Assert
actual.Should().Be(expected);
}
}