0

I have tried

Option 1

         var invocations = 0;
        _mockSqsMessageManager.Setup(x => x.GetMessages())
            .ReturnsAsync(() => invocations > 0 ? new List<SqsMessage>() : messages)
            .Callback(() =>
            {
                invocations++;
            });

Option 2

            _mockSqsMessageManager.Setup(x => x.GetMessages())
            .ReturnsAsync(messages)
            .Callback(() =>
            {
                _mockSqsMessageManager.Setup(x => x.GetMessages())
                    .ReturnsAsync(new List<SqsMessage>());
            });

Option 3

            var invocations = 0;
        _mockSqsMessageManager.Setup(x => x.GetMessages())
            .ReturnsAsync(messages)
            .Callback(() =>
            {
                invocations++;
                if (invocations > 0)
                {
                    messages = new List<SqsMessage>();
                }
            });

Option 4

        _mockSqsMessageManager.Setup(x => x.GetMessages())
            .ReturnsAsync(() =>
            {
                var invocations = _mockSqsMessageManager.Invocations.Count(x => x.MatchingSetup.Expression.Body.ToString() == "x.GetMessages()");
                return invocations > 0 ? new List<SqsMessage>() : messages;
            });

Option 5

            _mockSqsMessageManager.SetupSequence(x => x.GetMessages())
            .ReturnsAsync(messages)
            .ReturnsAsync(new List<SqsMessage>());

None have worked reliably. Option 5 works but if I only have the exact amount of invocations. I may have more than 100+ invocations so I can't use SetupSequence.

Vergil C.
  • 1,046
  • 2
  • 15
  • 28
  • 1
    Here's a similar question https://stackoverflow.com/questions/11308328/setupsequence-in-moq with some other options. – juharr Sep 23 '22 at 13:34
  • I have answered my own question, please check. Your recommendation for the post prompted me to think about thread safety. I have a working solution now with locks. – Vergil C. Oct 04 '22 at 09:44

1 Answers1

1

My issue was thread safety since the mock was being called from a TransformBlock of TPL

Creating a lock and ensuring unique access to the resource worked.

object getMessagesLocker = new();
var fetchedMessages = false;
var noMessages = Enumerable.Empty<SqsMessage>();

_mockSqsMessageManager.Setup(x => x.GetMessages())
.ReturnsAsync(() =>
{
    lock (getMessagesLocker)
    {
        if (fetchedMessages == false)
        {
            fetchedMessages = true;
            return messages;
        }

        return noMessages;
    }
});

BTW, I tested option 4 on single-threaded execution where mock is called only on from the main thread and that works fine.

Vergil C.
  • 1,046
  • 2
  • 15
  • 28