3

I have a function that returns a status like this:

public async Task<Result> UpdateWeight(string id, int weight)
        {
            var data = await service.GetData(id);

            if (data != null)
            {
                var user = await GetInfo(data.UserId);

                var changedWeight = await UpdateWeight(newWeight, user);

                if (!changedWeight)
                {
                    return new ChangeWeightResult("Weight not updated");
                }

                return new ChangeWeightResult(newWeight);
            }

            return new ChangeWeightResult("Error changing weight");
        }

And I'm trying to set up a unit test (xUnit - NSubstitute) for it.

public async Task UpdateUserAvatar_WhenCalled_ReturnChangedAvatarSuccess()
        {
            //Arrange
            var id = "id";
            var newWeight = 30;

            var data = new DataEntity
            {
                Id = id
            };

            var user = new User
            {
                UserId = "id"
            };


            service.GetData(Arg.Any<string>()).Returns(data);
            service.GetUser(Arg.Any<string>()).Returns(user);


            //Act
            var result = await service.UpdateWeight(data.Id, newWeight;
            

            //Assert
            result.IsSuccessful.Should().BeTrue();
            result.Weight.Should().Be(newWeight);

        }

However I keep stumble upon error such as null for the memory cache (CacheEntryFake) when I don't return the User or "Cannot return value of type Task 1 for IMemoryCache.CreateEntry"

These are all the functions that I called within the function that I want to test

public async Task<DataEntity> GetData(string id)
        {
            var data = await memoryCache.GetOrCreateAsync(id, CacheFactory);

            return data;
        }
internal async Task<DataEntity> CacheFactory(ICacheEntry cache)
        {
            var data = await GetDataFromDb(cache.Key.ToString());

            if (IsExpiredSession(data))
            {
                cache.Dispose();
            }
            else
            {

                cache.SetAbsoluteExpiration(relative);
            }

            return data;
        }
private async Task<bool> GetInfo(string id)
        {
            if(setting.CacheTimeout > 0)
            {
              return await 
           memoryCache.GetOrCreateAsync(id, InfoCacheFactory):
            }
           
            return id;
        }
Noelia
  • 89
  • 10
  • What is your specific error content, can you show it? Can you get the data when you call it? – Tupac Aug 25 '21 at 09:32
  • Can you provide a minimum reproducible example please. I can see the GetData method provided invokes the cache GetOrCreateAsync method, but I can only see `service.GetData(id);` in the SUT which is (apparently) being mocked (Can this method be mocked? Are you mocking an interface or a virtual method?). – rgvlee Aug 28 '21 at 07:25
  • My specific error content looks like this: System.ArgumentNullException: Value cannot be null. (Parameter: 'key') at rgvlee.Core.Common.Helper/EnsureArgument.IsnotNull(T) at MemoryCache.Testing.Common.CacheEntryFake – Noelia Aug 30 '21 at 03:54
  • @Chaodeng When I debug into the test the exception was triggered on this line = await memoryCache.GetOrCreateAsync(id, InfoCacheFactory); of the GetInfo func – Noelia Aug 30 '21 at 04:25
  • @rgvlee I am mocking a method. The exception was thrown at the GetInfo() func at the GetOrCreateAsync statement, seems like the id was missing or null. – Noelia Aug 30 '21 at 04:27
  • Ah, so you're using MemoryCache.Testing.NSubstitute for the memory cache mock and you're getting a null guard error in that library as the cache entry key is null. As you mention, the cache entry key `id` is probably null. – rgvlee Aug 30 '21 at 04:43
  • @rgvlee exactly. I am stuck on the part to pass the id in, because the id passed in the GetInfo(string id) was taken from the GetData() func. I did service.GetData(Arg.Any()).Returns(data); then await memoryCache.GetOrCreateAsync(Id, (cache) => Task.FromResult(Info)); but the exeception was still thrown. – Noelia Aug 30 '21 at 05:00
  • Your service substitute looks fine, the GetData method will return the data entity as per your arrange. The issue may be in your CacheFactory, it's hard to tell without a minimum reproducible example and I can't help further until that's provided. – rgvlee Aug 30 '21 at 07:00
  • @rgvlee Sure, what should a minimum reproducible example be like? Sorry I was just trying to understand what kind of other information you might need? – Noelia Aug 30 '21 at 07:38

0 Answers0