Question

I have been trying to figure out how to cover my internal function that is used as call back when getting item from a cache. I have a CacheService that accepts key and Func. The Func is called when the item is not in cache.

This sample code was based from anothe suggestion here in SO, but the cacheService.Get method always returns null and the WhenCalled was never called.

I understand its debatable whethere I should cover this internal method, but for start im trying possible way to cover this without creating a new class just for this internal methods. Appreciated your help.

CacheService.cs

    public T Get<T>(string key, Func<T> funcWhenNotExist)
    {
        if (!Exists(key))
        {
            var result = funcWhenNotExist();
            Cache.Put(key, result);
        }

        return DoSomethingWithRetry(() => (T)Cache.Get(key), MAXRETRY);
    }

SomeService.cs

    public SomeDto GetSomeDto(string dtoAlias)
    {
           string cacheKey = "whatever";
           var someDto = cacheService.Get(cacheKey, () => GetSomeDtoInternal(dtoAlias));

           return someDto
    }

    internal SomeDto GetSomeDtoInternal(string dtoAlias
    {
    //do more here
    }

SomeServiceTest.cs

    // Arrange
        SomeDto stubResult = new SomeDto();
        cacheService.Stub(s => s.Get(Arg<string>.Is.Anything, Arg<Func<SomeDto>>.Is.Anything)).WhenCalled(m =>
        {
            var func = (Func<SomeDto>) m.Arguments[1];
            stubResult = func();
        }).Return(stubResult);

        // Act
        var result = service.GetSomeDto("whateveralias");
Was it helpful?

Solution

Here is a working example of CacheService stub:

cacheService
    .Stub(s => s.Get(Arg<string>.Is.Anything, Arg<Func<SomeDto>>.Is.Anything))
    .WhenCalled(m =>
        {
            var func = (Func<SomeDto>)m.Arguments[1];
            m.ReturnValue = func();
        })
    .Return(null);

You was getting null because m.ReturnValue wasn't set. So default was used a a value to return.
Return() argument is ignored in case of WhenCalled() usage - and this is confusing very often.

Here is also a bit different solution:
I personally prefere to use Do() handler rather than WhenCaled() in similar cases. It allows to write the stub handler in a type safe way:

cacheService
    .Stub(s => s.Get(Arg<string>.Is.Anything, Arg<Func<SomeDto>>.Is.Anything))
    .Do((Func<string, Func<SomeDto>, SomeDto>)((key, funcWhenNotExist) =>
        {
            return funcWhenNotExist();
        }));

Please note Return(null) isn't necessary here anymore. The only thing you need to do is to explicitly convert lambda to stubbed method signature.

Hope that helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top