0

The interface I want to mock

interface Proxy
{
    Task Send();
}

Usage

class MultiProxy
{
    IEnumerable<Proxy> _proxies;
    MultiProxy(IEnumerable<Proxy> proxies)
    { _proxies = proxies; }

    async Task Send()
    {
        _proxies.Select(proxy => proxy.Send());
    }

    // The test method written here for convenience
    private async Task Mock()
    {
        var mocks = Enumerable.Range(0, 2)
            .Select(_ =>
            {
                var mock = new Mock<Proxy>();
                mock.Setup(proxy => proxy.Send())
                    .Returns(Task.CompletedTask);
                return mock;
            });
        //.ToList();
        var mockProxies = mocks.Select(mock => mock.Object);
        var mulProxies = new MultiProxy(mockProxies);

        await mulProxies.Send();

        foreach (var mock in mocks)
        {
            mock.Verify(proxy => proxy.Send(), Times.Once);
        }
    }
}

The Mock() method would fail.
However, if I un-comment the ToList() then the Mock() method would success.

I want to know why this happens.

Moq version: 4.14.5

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
sindo
  • 19
  • 3
  • Welcome to StackOverlfow. Without `ToList` you just defined a "query" / "job" but you do not materialize it. In other words you haven't executed the code which is inside your `Select` until you call the `foreach`. – Peter Csala Sep 07 '20 at 15:28
  • This mechanism is called Deferred Evaluation. [Here](https://stackoverflow.com/questions/2530755/difference-between-deferred-execution-and-lazy-evaluation-in-c-sharp) you can find a great discussion about it. – Peter Csala Sep 07 '20 at 15:30
  • Thank you for your comment. If the query is not evaluated, why `mulProxies.Send()` is executed successfully? I think mulProxies.Send() has to traverse all the mock proxies? – sindo Sep 08 '20 at 02:47
  • Your `mulProxies.Send` does not do anything useful. It creates another query definition which is discarded immediately. So it won't call the underlying proxies. If you wish to call them then you can do either this: `public void Send() => _proxies.Select(proxy => proxy.Send()).ToList();` or this: `public async Task Send() { foreach (var proxy in _proxies) await proxy.Send(); }` – Peter Csala Sep 08 '20 at 07:34

0 Answers0