views:

85

answers:

3

I am trying to unit test / verify that a method is being called on a dependency, by the system under test (SUT).

  • The depenedency is IFoo.
  • The dependent class is IBar.
  • IBar is implemented as Bar.
  • Bar will call Start() on IFoo in a new (System.Threading.Tasks.)Task, when Start() is called on Bar instance.

Unit Test (Moq):

    [Test]
    public void StartBar_ShouldCallStartOnAllFoo_WhenFoosExist()
    {
        //ARRANGE

        //Create a foo, and setup expectation
        var mockFoo0 = new Mock<IFoo>();
        mockFoo0.Setup(foo => foo.Start());

        var mockFoo1 = new Mock<IFoo>();
        mockFoo1.Setup(foo => foo.Start());


        //Add mockobjects to a collection
        var foos = new List<IFoo>
                       {
                           mockFoo0.Object,
                           mockFoo1.Object
                       };

        IBar sutBar = new Bar(foos);

        //ACT
        sutBar.Start(); //Should call mockFoo.Start()

        //ASSERT
        mockFoo0.VerifyAll();
        mockFoo1.VerifyAll();
    }

Implementation of IBar as Bar:

    class Bar : IBar
    {
        private IEnumerable<IFoo> Foos { get; set; }

        public Bar(IEnumerable<IFoo> foos)
        {
            Foos = foos;
        }

        public void Start()
        {
            foreach(var foo in Foos)
            {
                Task.Factory.StartNew(
                    () =>
                        {
                            foo.Start();
                        });
            }
        }
    }

Moq Exception:

*Moq.MockVerificationException : The following setups were not matched:
IFoo foo => foo.Start() (StartBar_ShouldCallStartOnAllFoo_WhenFoosExist() in
FooBarTests.cs: line 19)*
A: 

(As per Fredrik Mörk's comment)

This is how I got this to work (without using Moq).

Updated Unit Test:

    [Test]
    public void StartBar_ShouldCallStartOnAllFoo_WhenFoosExist()
    {
        MockFoo mockFoo0 = new MockFoo();
        MockFoo mockFoo1 = new MockFoo();

        IEnumerable<IFoo> foos = new List<IFoo>
                                    {
                                        mockFoo0,
                                        mockFoo1
                                    };

        IBar sut = new Bar(foos);

        sut.Start();

        Thread.Sleep(TimeSpan.FromSeconds(1));

        Assert.True(mockFoo0.IsStarted);
        Assert.True(mockFoo1.IsStarted);
    }

The mock IFoo implementation with a flag to assert against.

    class MockFoo : IFoo
    {
        public bool IsStarted { get; set; }

        public MockFoo()
        {
            IsStarted = false;
        }

        public void Start(CancellationToken cancelToken)
        {
            IsStarted = true;
        }
    }
StevenH
+1  A: 

MoQ isn't the problem, it's just the asynchronous nature of the sut. All you need to do is add this:

sut.Start(); 
Thread.Sleep(TimeSpan.FromSeconds(1));
dpurrington
Better yet would be to expose some way to wait on the Task.
Joe White
A: 

Your tests uses too much implementation detail, IEnumerable<IFoo> types. Whenever I have to start testing with IEnumerable it always creates some friction.

Gutzofter