Skip to content

Cooperation with Other Frameworks

Akira Sugiura edited this page Oct 12, 2015 · 7 revisions

Prig doesn't support the feature of traditional mocking frameworks, because I believe it can be done by just using them if they are OSS library 😉

Let's think about the test for the following class:

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace CooperationWithOther
{
    public class NotifyingObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        int m_valueWithRandomAdded;
        public int ValueWithRandomAdded
        {
            get { return m_valueWithRandomAdded; }
            set
            {
                m_valueWithRandomAdded = value;
                m_valueWithRandomAdded += new Random((int)DateTime.Now.Ticks).Next();
                OnPropertyChanged();
            }
        }

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var handler = PropertyChanged;
            if (handler == null)
                return;

            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

I think that you maybe want to test that "ValueWithRandomAdded should raise PropertyChanged event with its name." or "ValueWithRandomAdded should hold passed value + Random.Next().". About the latter, I will introduce cooperation examples to test with using Moq, NSubstitute, Rhino Mocks and FakeItEasy.

As of common preparation, add the Indirection Stub for Random.Next(). Install Prig, and Add Prig Assembly for mscorlib in each test project:

After the Stub Settings File is added, execute the following commands to copy the Indirection Stub Setting for class Random to clipboard:

PM> [System.Random] | Find-IndirectionTarget | Get-IndirectionStubSetting | Clip

Then, paste it to the Stub Settings File mscorlib.v4.0.30319.v4.0.0.0.prig. Now, let's take a look at how to cooperate with each mocking framework!

Moq

This is cooperation examples for Moq.

using CooperationWithOther;
using Moq;
using NUnit.Framework;
using System;
using System.ComponentModel;
using System.Prig;
using Urasandesu.Prig.Delegates;
using Urasandesu.Prig.Framework;

namespace CooperationWithOtherTest
{
    [TestFixture]
    public class MoqTest
    {
        [Test]
        public void ValueWithRandomAdded_should_hold_passed_value_plus_random_value()
        {
            using (new IndirectionsContext())
            {
                // Arrange
                var notifyingObject = new NotifyingObject();

                var mockNext = new Mock<IndirectionFunc<Random, int>>();
                mockNext.Setup(_ => _(It.IsAny<Random>())).Returns(10);
                PRandom.Next().Body = mockNext.Object;

                
                // Act
                notifyingObject.ValueWithRandomAdded = 32;
                var actual = notifyingObject.ValueWithRandomAdded;

                
                // Assert
                mockNext.Verify(_ => _(It.IsAny<Random>()), Times.Once());
                Assert.AreEqual(42, actual);                
            }
        }
    }
}

NSubstitute

This is cooperation examples for NSubstitute.

using CooperationWithOther;
using NSubstitute;
using NUnit.Framework;
using System;
using System.ComponentModel;
using System.Prig;
using Urasandesu.Prig.Delegates;
using Urasandesu.Prig.Framework;

namespace CooperationWithOtherTest
{
    [TestFixture]
    public class NSubstituteTest
    {
        [Test]
        public void ValueWithRandomAdded_should_hold_passed_value_plus_random_value()
        {
            using (new IndirectionsContext())
            {
                // Arrange
                var notifyingObject = new NotifyingObject();

                var mockNext = Substitute.For<IndirectionFunc<Random, int>>();
                mockNext(Arg.Any<Random>()).Returns(10);
                PRandom.Next().Body = mockNext;


                // Act
                notifyingObject.ValueWithRandomAdded = 32;
                var actual = notifyingObject.ValueWithRandomAdded;


                // Assert
                mockNext.Received(1)(Arg.Any<Random>());
                Assert.AreEqual(42, actual);
            }
        }
    }
}

Rhino Mocks

This is cooperation examples for Rhino Mocks.

using CooperationWithOther;
using NUnit.Framework;
using Rhino.Mocks;
using System;
using System.ComponentModel;
using System.Prig;
using Urasandesu.Prig.Delegates;
using Urasandesu.Prig.Framework;

namespace CooperationWithOtherTest
{
    [TestFixture]
    public class RhinoMocksTest
    {
        [Test]
        public void ValueWithRandomAdded_should_hold_passed_value_plus_random_value()
        {
            using (new IndirectionsContext())
            {
                // Arrange
                var notifyingObject = new NotifyingObject();

                var mockNext = MockRepository.GenerateStub<IndirectionFunc<Random, int>>();
                mockNext.Stub(_ => _(Arg<Random>.Is.Anything)).Return(10);
                PRandom.Next().Body = mockNext;


                // Act
                notifyingObject.ValueWithRandomAdded = 32;
                var actual = notifyingObject.ValueWithRandomAdded;


                // Assert
                mockNext.AssertWasCalled(_ => _(Arg<Random>.Is.Anything), options => options.Repeat.Once());
                Assert.AreEqual(42, actual);
            }
        }
    }
}

FakeItEasy

This is cooperation examples for FakeItEasy.

using CooperationWithOther;
using FakeItEasy;
using NUnit.Framework;
using System;
using System.ComponentModel;
using System.Prig;
using Urasandesu.Prig.Delegates;
using Urasandesu.Prig.Framework;

namespace CooperationWithOtherTest
{
    [TestFixture]
    public class FakeItEasyTest
    {
        [Test]
        public void ValueWithRandomAdded_should_hold_passed_value_plus_random_value()
        {
            using (new IndirectionsContext())
            {
                // Arrange
                var notifyingObject = new NotifyingObject();

                var mockNext = A.Fake<IndirectionFunc<Random, int>>();
                A.CallTo(() => mockNext(A<Random>._)).Returns(10);
                PRandom.Next().Body = mockNext;


                // Act
                notifyingObject.ValueWithRandomAdded = 32;
                var actual = notifyingObject.ValueWithRandomAdded;


                // Assert
                A.CallTo(() => mockNext(A<Random>._)).MustHaveHappened();
                Assert.AreEqual(42, actual);
            }
        }
    }
}

Huh? Do you say "I think all of those probably look like the same example."? Yes, that's right. The most important thing is just one, "Be conscious making a mock for the delegate". Please feel free to select it which has such feature! ☺️

Complete source code is here.