skip to Main Content

I have a simple wrapper for stackexchange redis:

public interface IRedisClient
{        
    Task<RedisResult> ScriptEvaluate(LuaScript script, object parameters);
}

I have a method that calls ScriptEvaluate

public class Foo
{
    private readonly IRedisClient _client;

    public Foo(IRedisClient client)
    {
        _client = client;
    }

    public void RunScript()
    {
        _client.ScriptEvaluate(LuaScript.Prepare(""), new object());
    }
}

Now when I use NSubstitute to mock IRedisClient that is injected to Foo and then call RunScript

public void Test()
{
    _foo = new Foo(Substitute.For<IRedisClient>());
    _foo.RunScript();
}

I get the following error:

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.

As far as I can see Nsubstitute/Castle internals do not manage to work with RedisResult properly. I did not manage to find out any workarounds.

Is it possible to do something with this?

P.S. I get the same error when I try to configure the mock to return a value (same exception):

_client
    .ScriptEvaluate(null, null)
    .ReturnsForAnyArgs(RedisResult.Create((RedisKey)"result"));

2

Answers


  1. RedisResult is an abstract type, but there are static Create methods for common scenarios, and a few static properties such as EmptyArray, NullArray, etc. I can’t tell you how to configure your particular faking layer, but ultimately, I’d expect something involving RedisResult.Create

    Login or Signup to reply.
  2. I was curious about why mocking the abstract RedisResult was not a simple solution.

    This appears to be an issue with NSubstitute’s implementation.

    Using the following to try and recreate the problem

    public class Foo {
        private readonly IRedisClient _client;
    
        public Foo(IRedisClient client) {
            _client = client;
        }
    
        public Task<RedisResult> RunScript() {
            return _client.ScriptEvaluate(LuaScript.Prepare(""), new object());
        }
    }
    

    I was able to reproduce it using NSubstitute but was able to exercise the test to completion when using another mocking framework (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);
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search