Skip to content
This repository has been archived by the owner on Jun 30, 2023. It is now read-only.

Xunit: Moq Setup doesn't return expected value #101

Open
fsodano13 opened this issue Apr 1, 2023 · 3 comments
Open

Xunit: Moq Setup doesn't return expected value #101

fsodano13 opened this issue Apr 1, 2023 · 3 comments

Comments

@fsodano13
Copy link

fsodano13 commented Apr 1, 2023

Hi, everyone.
I've implemented a service that sends sms to some devices by means of AWS SNS Service.
The service checks for each device if it exists in a whitelist table. If the device isn't found, the sms is sent to a fallback number.

So, I've a WhiteListUser class:

public class WhiteListUser
{
    [Key]
    public string Device { get; set; }

    public string Username { get; set; }

    public bool IsFallback { get; set; }
}

An application context :

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {
    }

    public DbSet<WhiteListUser> WhiteListUsers { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        builder.Entity<WhiteListUser>().HasData(new WhiteListUser
        {
            Device = "+39370XXXXXXX",
            Username = "FALLBACK",
            IsFallback = true
        });
    }
}

and the service:

public interface ISmsService
{
    Task<IList<SendSmsResponse>> SendSmsAsync(SendSms @event, CancellationToken token);
}

public class SNSService : ISmsService
{
    private readonly IAwsProvider _awsProvider;
    private readonly ILogger<SNSService> _logger;
    private readonly IHostEnvironment _environment;
    private readonly IGenericRepository<WhiteListUser> _repository;

    public SNSService(IHostEnvironment environment, IGenericRepository<WhiteListUser> repository, IAwsProvider awsProvider, ILogger<SNSService> logger)
    {
        _awsProvider = awsProvider;
        _logger = logger;
        _environment = environment;
        _repository = repository;
    }

    public async Task<IList<SendSmsResponse>> SendSmsAsync(SendSms @event, CancellationToken cancellationToken)
    {
        if (_environment.IsDevelopment())
        {
            var fallbackNumber = (await _repository.Find(u => u.IsFallback)).First().Device;
            int i = 0;
            while (i < @event.Devices.Count)
            {
                var device = @event.Devices[i];
                var users = await _repository.Find(u => u.Device == device);
                if (users?.ToList().Count == 0)
                {
                    @event.Devices[i] = fallbackNumber;
                }
                i++;
            }
        }
        var response = await _awsProvider.SendSmsAsync(@event.Devices, @event.Message, cancellationToken);
        return response;
    }
}

SendSms event is a record with a message and a list of devices:

public record SendSms
{
    public string Message { get; set; }
    public List<string> Devices { get; set; }
}

When I try to run this test, it fails:

public class SNSServiceTest
{
    private readonly ISmsService _sut;
    private readonly Mock<IAwsProvider> _awsProviderMoq;
    private readonly Mock<ILogger<SNSService>> _loggerMoq;
    private readonly Mock<IHostEnvironment> _hostEnvironmentMoq;
    private readonly Mock<IGenericRepository<WhiteListUser>> _repositoryMoq;

    public SNSServiceTest()
    {
        _awsProviderMoq = new Mock<IAwsProvider>();
        _loggerMoq = new Mock<ILogger<SNSService>>();
        _hostEnvironmentMoq = new Mock<IHostEnvironment>();
        _repositoryMoq = new Mock<IGenericRepository<WhiteListUser>>();

        _sut = new SNSService(_hostEnvironmentMoq.Object,
                              _repositoryMoq.Object,
                              _awsProviderMoq.Object,
                              _loggerMoq.Object);
    }

   

    [Fact]
    public async Task Does_Replace_Only_Not_In_Whitelist_Numbers_With_Fallback_In_Dev_Env()
    {
        // Arrange
        var @event = new SendSms
        {
            Message = "pippo",
            Devices = new List<string>
            {
                "unknown",
                WhiteListFixtures.FallbackUser.Device,
                WhiteListFixtures.WhiteListUser.Device
            }
        };

        _repositoryMoq
          .Setup(x => x.Find(c => c.IsFallback))
          .ReturnsAsync(new List<WhiteListUser> { WhiteListFixtures.FallbackUser });

        _repositoryMoq
           .Setup(x => x.Find(c => c.Device == WhiteListFixtures.FallbackUser.Device))
           .ReturnsAsync(new List<WhiteListUser> { WhiteListFixtures.FallbackUser });

        _repositoryMoq
          .Setup(x => x.Find(c => c.Device == WhiteListFixtures.WhiteListUser.Device))
          .ReturnsAsync(new List<WhiteListUser> { WhiteListFixtures.WhiteListUser });

        _hostEnvironmentMoq.Setup(x => x.EnvironmentName).Returns(Environments.Development);

        // Act
        await _sut.SendSmsAsync(@event, CancellationToken.None);

        // Assert
        _awsProviderMoq
            .Verify(x => x.SendSmsAsync(
                It.Is<IList<string>>(l => l.Count == 3 &&
                                          l[0].Equals(WhiteListFixtures.FallbackUser.Device) &&
                                          l[1].Equals(WhiteListFixtures.FallbackUser.Device) &&
                                          l[2].Equals(WhiteListFixtures.WhiteListUser.Device)),
                "pippo",
                CancellationToken.None));
    }
}

where Fixtures are:

public class WhiteListFixtures
{

public static WhiteListUser FallbackUser => new WhiteListUser
{
    Device = _fallbackNumber,
    Username = "Test1",
    IsFallback = true,
};

public static WhiteListUser WhiteListUser = new WhiteListUser
{
    Device = _whiteListNumber,
    Username = "Test2",
    IsFallback = false,
};

private static string _fallbackNumber = "+393701002134";
private static string _whiteListNumber = "+393702223344";

}

it seems that these two setups are not working, so devices are never found and all the devices are so replaced, also the third one that is in the whitelist:

        _repositoryMoq
           .Setup(x => x.Find(c => c.Device == WhiteListFixtures.FallbackUser.Device))
           .ReturnsAsync(new List<WhiteListUser> { WhiteListFixtures.FallbackUser });

        _repositoryMoq
          .Setup(x => x.Find(c => c.Device == WhiteListFixtures.WhiteListUser.Device))
          .ReturnsAsync(new List<WhiteListUser> { WhiteListFixtures.WhiteListUser });

this is the error message:

UnitTests.Services.SNSServiceTest.Does_Replace_Only_Not_In_Whitelist_Numbers_With_Fallback_In_Dev_Env
 Source: SNSServiceTest.cs line 34
 Duration: 11 ms

Message: 
Moq.MockException :
Expected invocation on the mock at least once, but was never performed: x => x.SendSmsAsync(It.Is<IList>(l => ((l.Count == 3 && l[0].Equals(WhiteListFixtures.FallbackUser.Device)) && l[1].Equals(WhiteListFixtures.FallbackUser.Device)) && l[2].Equals(WhiteListFixtures.WhiteListUser.Device)), "pippo", CancellationToken)

Performed invocations:

MockIAwsProvider:2 (x):

  IAwsProvider.SendSmsAsync(["+39370XXXXXXX", "+39370XXXXXXX", "+39370XXXXXXX"], "pippo", CancellationToken)

Stack Trace: 
Mock.Verify(Mock mock, LambdaExpression expression, Times times, String failMessage) line 330
Mock1.Verify[TResult](Expression1 expression) line 810
SNSServiceTest.Does_Replace_Only_Not_In_Whitelist_Numbers_With_Fallback_In_Dev_Env() line 67
--- End of stack trace from previous location ---

I don't know what am I doing wrong, if the test or the implementation.
I was expecting: IAwsProvider.SendSmsAsync(["+39370XXXXXXX", "+39370XXXXXXX", "+39370YYYYYYY"], "pippo", CancellationToken)

Can any expert help me?
Thanks in advance

@fsodano13
Copy link
Author

Can someone help me???

@stakx
Copy link
Contributor

stakx commented Apr 4, 2023

@fsodano13, this issue tracker focuses on the development of Moq itself, not on fixing user code. Your query might meet a larger audience on sites such as Stack Overflow, or in Moq's Discord chat.

@fsodano13
Copy link
Author

HI @stakx I'm not asking for debugging my code. I do not understand why
the call await _repository.Find(u => u.Device == device) doesn't return expected feature.
I want to understand if i'm not using well the library or there is some issue in that.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants