chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
In the following example I reported a simplified case of integration test where I am faking a private member and I check the arguments used on its constructor calls in two different cases.

How can I write my expectations in FakeAMember to guarantee that test TestConstructorWithoutParams fails if someone changes the constructor of the class ClassUnderTest as depicted below.
That is, how can I write that the class ClassUnderTest is going to call the constructor of the class AMember with no parameters?

Current constructor:

            internal ClassUnderTest()
            {
                _aMember = new AMember();
            }

New constructor (TestConstructorWithoutParams does not fail):

            internal ClassUnderTest()
            {
                _aMember = new AMember(5);
            }



Thanks in advance
-Simo


Example:


        class FakeAMember
        {
            private readonly Mock<AMember> _mock = null;

            public FakeAMember(int i)
            {
                _mock = MockManager.Mock<AMember>();

                _mock.ExpectConstructor().Args(i);
            }

            public FakeAMember()
            {
                _mock = MockManager.Mock<AMember>();

                _mock.ExpectConstructor();
            }
        }

        class AMember
        {
            public AMember(int i) { }
            public AMember() { }
        }

        class ClassUnderTest
        {
            private AMember _aMember;

            internal ClassUnderTest()
            {
                _aMember = new AMember();
            }

            internal ClassUnderTest(int i)
            {
                _aMember = new AMember(i);
            }
        }

       private ClassUnderTest _classUnderTest;
        private FakeAMember _fakeAMember;

        #region SetUp and TearDown
        [SetUp]
        public void SetUp()
        {
            if (!MockManager.IsInitialized)
            {
                MockManager.Init();
            }
        }

        [TearDown]
        public void TearDown()
        {
            MockManager.Verify();
        }

        #endregion

        [Test]
        public void TestConstructorWithoutParams()
        {
            _fakeAMember = new FakeAMember();
            _classUnderTest = new ClassUnderTest();
        }

        [Test]
        public void TestConstructorWithOneParam()
        {
            _fakeAMember = new FakeAMember(1);
            _classUnderTest = new ClassUnderTest(1);
        }
asked by simo (1.3k points)

6 Answers

0 votes
Hi Simo,

There is kind of a hack you can use to do that - use ExpectConstructorAndThrow with conditional expectation.
Here's an example:
[Test]
public void TestConstructorWithOneParam()
{
    Mock mock = MockManager.Mock<AMember>(Constructor.NotMocked);
    mock.ExpectConstructorAndThrow(new Exception("Constractor with arguments should not be called"))
                                    .When(Check.IsAny());
    
    _classUnderTest = new ClassUnderTest(1);
}


In the example above an exception will be thrown only if the contractor is called with arguments.
Note: You should remove the Verify from the TearDown method in order to make it work.

Please let me know if it helps.
answered by ohad (35.4k points)
0 votes
But if I remove Verify from the TearDown method, how can I check that all the other expected calls have been actually called/consumed?

Is there another way to verify that the faked member is called on the ctor with no params?

Thanks
-Simo
answered by simo (1.3k points)
0 votes
Hi Simo,

Hmm... My opinion is that putting the verification in the TearDown method is not such a good idea.
Here are the reasons:
1. When the verification fails you don't know what test method failed.
2. Do you really need to perform verification on each test?
One of the best practices for unit tests is that test method should assert one thing. That way when a test fails you know immediately what's broken.
3. If you verify each faked method in the tests it can lead to brittle tests that will break on every small change.

It may be better to do the verify explicitly on each test method that needs the verification.

That been said if you prefer to put the verification in the tear down method you can still put this test in separate test class that is not calling Verify at the tear down.
answered by ohad (35.4k points)
0 votes
Hi,

To be honest I do not completely agree with you about the possibility to remove Verify call from my TearDown method.
I would like to maintain it to catch extra expectations and so on...

However, I was wondering whether there is the possibility to set an handler where I can perform my custom checks, such as I already can do for the other methods (using MethodSettings method).

E.g.

_mock = MockManager.Mock<AMember>();

_mock.MethodSettings("aMethodName").MockMethodCalled += CheckArgs; 
answered by simo (1.3k points)
0 votes
Hi Simo,

You can do that but since you are interested in the constructor you should
use ".ctor" as an argument to MethodSettings

Example:
public static void CheckArgs(object sender, MockMethodCallEventArgs eventArgs)
{
    if (eventArgs.SentArguments.Length > 0)
    {
        Assert.Fail("Constractor with arguments should not be called");
    }
}

[Test]
public void Test()
{
    Mock mock = MockManager.Mock<AMember>();
    mock.MethodSettings(".ctor").MockMethodCalled += CheckArgs;

    _classUnderTest = new ClassUnderTest(1);
}
answered by ohad (35.4k points)
0 votes
Ok.

Thanks
-Simo
answered by simo (1.3k points)
...