Head scratching with a TargetParameterCountException


Ever introduced an extra parameter on a method, tracked all its usages and made the compiler happy by providing a corresponding extra argument in all the calls of that method?

Sure you have. Either that or removed a parameter from a method.

You just change the signature of the method, adding the new parameter. Then you track down all usages of that method, using “Find all usages” in Visual Studio, or simply by compiling and working through the list of errors.

When you commit it, you would get a a diff much like:

-internal virtual int MethodWithParameterChange(string someString, bool someBool)
+internal virtual int MethodWithParameterChange(string someString, int someInt, bool someBool)
 internal int MethodUsingInstance()
 {
-    var x = _instance.MethodWithParameterChange("this is a string", true);
+    var x = _instance.MethodWithParameterChange("this is a string", 5, true);
     return x * 2;
 }
 var instanceToUse = Mock.Of<ClassToMock>();
 Mock.Get(instanceToUse)
     .Setup(instance => instance.MethodWithParameterChange(
-        It.IsAny<string>(), It.IsAny<bool>()))
+        It.IsAny<string>(), It.IsAny<int>(), It.IsAny<bool>()))


No biggie. Compiler is happy again. You’re good to go. It compiles. Let’s ship.

Uh oh. Wait. Maybe not so fast. You have unit tests after all. So let’s run these first. You know, because, well, you never know.

Ouch. Failures.

Now, how the heck did that happen?

You just changed the method signature and the calls. Yes, the arguments are passed, but you didn’t change the code in the method yet, so it should still behave as before. Those tests have no right to start misbehaving. They all should still pass. Darn it.

Parameter Count Mismatch

System.Reflection.TargetParameterCountException : Parameter count mismatch.

Huh?

You tracked all the calls. The compiler was happy!

You didn’t go anywhere near reflection.

When you debug one of the tests, sure enough, the exception is raised at a line with a call to the method you just changed. The number of parameters passed to the call is absolutely spot on.

Exception

Going back up the call stack doesn’t help much. That just shows the act part of your test was being executed when the exception occurred.

Call of changed method

Mystified

What the blazes is going on then?

Well, the method is called on a field member holding an instance of a different class.

Exception producing code

The test must have injected that, so it must have been mocked in the test.

Sure enough. Exactly where it should be. In the arrange part of the test, right above the act part.

        [TestMethod]
        public void MethodUsingInstance_ShouldReturn_DoubleTheValueOfItsInstance()
        {
            // Arrange
            var instanceToUse = Mock.Of<ClassToMock>();
            Mock.Get(instanceToUse)
                .Setup(instance => instance.MethodWithParameterChange(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<bool>()))
                .Returns((string s, bool b) => 23);

            var cut = new ClassUnderTest(instanceToUse);

            // Act
            var returned = cut.MethodUsingInstance();

            // Assert
            Assert.AreEqual(46, returned);
        }

The Setup looks absolutely fine. No wonder. If it hadn’t, the compiler would have complained loudly.

Scratches head.

Turns to trusted friend Google. S/he comes up with interesting information, but it doesn’t get you much further.

Then, suddenly, out of the blue, you have a spark of inspiration.

That’s it!

The Setup call for the mocked instance only tells the mock for which method it has to return a value. It’s the Returns call that tells the mock what to do when the class under test actually calls that mocked method.

When you check it. Yup. The lambda in the Returns call still has the old number of parameters.

        [TestMethod]
        public void MethodUsingInstance_ShouldReturn_DoubleTheValueOfItsInstance()
        {
            // Arrange
            var instanceToUse = Mock.Of();
            Mock.Get(instanceToUse)
                .Setup(instance => instance.MethodWithParameterChange(
                    It.IsAny(), It.IsAny(), It.IsAny()))
                .Returns((string s, bool b) => 23);

            var cut = new ClassUnderTest(instanceToUse);

            // Act
            var returned = cut.MethodUsingInstance();

            // Assert
            Assert.AreEqual(46, returned);
        }

Oh, the joys of reflection and run time errors!

Tip

If you don’t need the returned value to use any of the argument values for the parameters of the mocked method, you can use empty brackets. Doing it like this ensures that the tests will not start failing when you change the number of parameters.

                .Returns(() => 23);


What reflection gotcha’s have had you scratching your head?



2 comments on “Head scratching with a TargetParameterCountException
  1. Manohar Kumar says:

    Wow.. you are a lifesaver

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Show Buttons
Hide Buttons