-
Notifications
You must be signed in to change notification settings - Fork 392
Description
I moved discussion from old PR to new issue.
@pape77 issue #158 (comment)
I have a similar issue with this "ghost branches" which are never covered.
My code looks like this
public class KeyProvider : IKeyProvider
{
private readonly IKeyRepository _repository;
private readonly IMemoryCache _cache;
public KeyProvider(IKeyRepository repository, IMemoryCache cache)
{
_repository = repository;
_cache = cache;
}
public async Task<Key> GetByUuidAndTypeAsync(Guid uuid, KeyType type, CancellationToken cancellationToken)
{
return await _cache.GetOrCreateAsync($"uuid-{uuid.ToString()}-key-{type}",
async entry => await _repository.FindOrCreateAsync(uuid, type, cancellationToken));
}
public class Key
{
public int Id { get; set; }
public Guid Uuid { get; set; }
[Required]
public Guid Kid { get; set; }
[Required]
public KeyType KeyType { get; set; }
}
public enum KeyType
{
Cenc,
Fairplay,
Aes
}
}
This code generates 4 branches, 2 of which I'm never able to cover
my tests:
public class KeyProviderTests
{
private readonly Mock _keyRepositoryMock;
private readonly MemoryCache _memoryCache;
private readonly Guid _testGuid = Guid.NewGuid();
private readonly KeyProvider _keyProvider;
public KeyProviderTests()
{
_memoryCache = new MemoryCache(new MemoryCacheOptions());
_keyRepositoryMock = new Mock<IKeyRepository>();
_keyProvider = new KeyProvider(_keyRepositoryMock.Object, _memoryCache);
}
[Theory(DisplayName = "Should call repository method with correct values")]
[InlineData(KeyType.Cenc)]
[InlineData(KeyType.Aes)]
[InlineData(KeyType.Fairplay)]
public async Task GetByUuidAndTypeAsync01(KeyType keyType)
{
_keyRepositoryMock.Setup(kr =>
kr.FindOrCreateAsync(_testGuid, keyType, It.IsAny<CancellationToken>()))
.ReturnsAsync(new Key());
await _keyProvider.GetByUuidAndTypeAsync(_testGuid, keyType, new CancellationToken());
_keyRepositoryMock.Verify(
kr => kr.FindOrCreateAsync(_testGuid, keyType, It.IsAny<CancellationToken>()), Times.Once);
}
[Theory(DisplayName = "Should get key from cache")]
[InlineData(KeyType.Cenc)]
[InlineData(KeyType.Aes)]
[InlineData(KeyType.Fairplay)]
public async Task GetByUuidAndTypeAsync02(KeyType keyType)
{
var cacheKey = $"uuid-{_testGuid.ToString()}-key-{keyType}";
_memoryCache.Set(cacheKey, new Key());
await _keyProvider.GetByUuidAndTypeAsync(_testGuid, keyType, new CancellationToken());
_keyRepositoryMock.Verify(
kr => kr.FindOrCreateAsync(_testGuid, keyType, It.IsAny<CancellationToken>()), Times.Never);
}
}
The generated branches in my coverage.json are (notice the MoveNext() thing):
"Keys.Application.Services.KeyProvider/<>c__DisplayClass3_0/<<GetByUuidAndTypeAsync>b__0>d": {
"System.Void Keys.Application.Services.KeyProvider/<>c__DisplayClass3_0/<<GetByUuidAndTypeAsync>b__0>d::MoveNext()": {
"Lines": {
"27": 9
},
"Branches": [
{
"Line": 27,
"Offset": 8,
"EndOffset": 14,
"Path": 0,
"Ordinal": 0,
"Hits": 3
},
{
"Line": 27,
"Offset": 81,
"EndOffset": 83,
"Path": 0,
"Ordinal": 2,
"Hits": 0
},
{
"Line": 27,
"Offset": 8,
"EndOffset": 119,
"Path": 1,
"Ordinal": 1,
"Hits": 0
},
{
"Line": 27,
"Offset": 81,
"EndOffset": 147,
"Path": 1,
"Ordinal": 3,
"Hits": 3
}
]
}
},
Line 27 in my code is precisely the async await one:
async entry => await _repository.FindOrCreateAsync(uuid, type, cancellationToken));
hope it's useful
Repro keys.zip