C# Unit Testing: Mock repository method that throws custom Exception with "Pose"

72 Views Asked by At

The method I'm testing has to throw a custom "ApiNotFoundException" when the searched entity is not found. I have no problems testing that as I can just write:

await Assert.ThrowsAsync<ApiNotFoundException>(async () => await _mockAccountHoldersRepository.Object.GetAccountHoldersList(_accountid.ToString(), true));

But the problem is that "GetAccountHoldersList" calls a static method in a class which doesn't have an interface.

I cannot modify the methods, only the tests, so I'm forced to use Pose (or Microsoft's "Fake") in order to Mock the static method and fake a result.

To test:

public Task<IQueryable<AccountHolder>> GetAccountHoldersList(string accountId, bool expandHolderType)
{
    var _accountId = UidResolver.MapUidToId(accountId); //=> static method

    var queryresult = _context
        .AccountHolders
        .Include(a => a.Account).AsQueryable();

    if (expandHolderType)
    {
        queryresult = queryresult.Include(ht => ht.HolderType).AsQueryable();
    }

    queryresult = queryresult.Where(ah => ah.AccountId == _accountId && ah.EndDate == null).AsQueryable();

    if ((!queryresult.Any()) || (accountId == null))
    {
        //=>This is the throw I need to test
        throw new ApiNotFoundException(ErrorString.AccountHoldersRepository.GetAccountHolders_NotFound, new { accountId });
    }

    return Task.FromResult(queryresult);
}

UidResolver:

public abstract partial class UidResolver
{
    protected static UidResolver Default { get; set; }

    public static long MapUidToId(string guid)
    {
        // Trivial or null case
        if (String.IsNullOrEmpty(guid))
        {
            return 0;
        }

        if (!Ids.TryGetValue(guid, out var value))
        {
            if (!Options.RefreshIfNotFound)
            {
                throw new ApiNotFoundException($"MapUuidToId: Key {guid} not found.");
            }

            if (Default?.TryRefreshUid(guid, out value) != true)
            {
                if (Options.ThrowNotFoundException)
                {
                    throw new ApiNotFoundException($"MapUuidToId: Key {guid} not found.");
                }
                else
                {
                    value = 0;
                }
            }
        }

        return value;
    }
}

Test method:

[Fact]
public async Task GetAccountList_ThrowsException_WhenNoData()
{
    _accountid = Guid.NewGuid();

    var acountHolders = new List<AccountHolder>();
    _mockDbContext
        .Setup(x => x.AccountHolders)
        .Returns(ApiDbContextMock.GetMockDbSet(acountHolders));

    //var cache = _mockDistributedCacheGrowth.Object;
    //UidResolver.AddUid(_accountid, 1, cache);

    Shim shim = Shim.Replace(() => UidResolver.MapUidToId(Is.A<string>()))
        .With(delegate (string guid) { return (long)1; });

    var actualResult = new List<AccountHolder>();

    PoseContext.Isolate(async () =>
    {
        await Assert.ThrowsAsync<ApiNotFoundException>(async () => await _mockAccountHoldersRepository.Object.GetAccountHoldersList(_accountid.ToString(), true));
    }, shim);
}

If I uncomment the two commented lines, testing works just fine (and I don't even need "Pose"), but I don't think it's a good idea to call the real method (and not a mocked one) during a test.

This line:

Shim shim = Shim.Replace(() => UidResolver.MapUidToId(Is.A<string>()))
            .With(delegate (string guid) { return (long)1; });

it's working fine (or at least not crashing), but the problem is I don't know then how to construct the

PoseContext.Isolate(async () => {});

part.

0

There are 0 best solutions below