Arranging/Asserting private method with params keyword

6 posts, 1 answers
  1. Gerard
    Gerard avatar
    4 posts
    Member since:
    Apr 2016

    Posted 05 May Link to this post

    I have a method such as:

    private bool DoAction(Type typeOfConsumer, params Object[] extraParams)

    I want to assert it is called, where the public equivalent is:

    Mock.Arrange(() => instanceOfClass.DoAction(Arg.IsAny<Type>()).MustBeCalled();

    works for the call

    instanceOfClass.DoAction(typeof(SomeType)); // No params, but does this matter?

    and I would expect the non-public to be

    Mock.NonPublic.Arrange(instanceOfClass, "DoAction", Arg.IsAny<Type>()).MustBeCalled();

    but my (NUnit) exception is System.MissingMemberException : Method 'DoAction' with the given signature was not found on type...

     

    It works with the public equivalent and

    It does not work with the non-public whether the method is made protected or private.

    I want to arrange and then assert that this method was called.

  2. Answer
    Svetlozar
    Admin
    Svetlozar avatar
    271 posts

    Posted 10 May Link to this post

    Hi,

    I am sorry for the misunderstanding.

    The important part here is the params parameter of the method and the way the compiler handles invocations to methods with such parameters. You can read more about it here.

    The public version works, because the compiler generates code that looks like this.
    Mock.Arrange(() => instanceOfClass.DoAction(Arg.IsAny<Type>(), new object[] { }).MustBeCalled();

    For the non public version you will need to add the array argument that the compiler adds at the place of the invocation. That is the same reason why you get the MissingMemberException, the invocation has 2 arguments - object and an array of objects.

    Here is an example

    Mock.NonPublic.Arrange(instanceOfClass, "DoAction", ArgExpr.IsAny<Type>(), ArgExpr.IsAny<Object[]>()).MustBeCalled();



    I hope that helps, let me know if you have other questions.

    Regards,
    Svetlozar
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items

     
     

     
  3. DevCraft R3 2016 release webinar banner
  4. Gerard
    Gerard avatar
    4 posts
    Member since:
    Apr 2016

    Posted 18 May in reply to Svetlozar Link to this post

    Svetlozar,

    Are you saying that my call to the private method DoAction() must be

    DoAction(typeof(SomeType), null);

    instead of

    DoAction(typeof(SomeType));

    ?

    Right now, asserting against 

    Mock.NonPublic.Arrange(instance, "DoAction", typeof(SomeType), ArgExpr.IsNull<Object[]>()).MustBeCalled();

    Gives me: Occurrence expectation failed. Expected at least 1 call. Calls so far: 0

    It works if I added null as the param Object[] parameter. But I can't change all the calls in existing code for testing purposes at this time so I'm trying to find a way to do this without making such modifications.

     

  5. Svetlozar
    Admin
    Svetlozar avatar
    271 posts

    Posted 20 May Link to this post

    Hello,

    I am sorry for the misunderstanding.

    You don't need to change DoAction invocations, you need to change the Arrange methods to match the invocation, because when you don't pass an argument for the params parameter, the compiler generates code as if you've passed an empty array. Here is a complete example.

    public class Foo
    {
        public bool PublicAction(Type type, params Object[] extraParams)
        {
            return DoAction(type, extraParams);
        }
     
        private bool DoAction(Type typeOfConsumer, params Object[] extraParams)
        {
            return false;
        }
    }

    And the test

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            Foo fo = new Foo();
            Mock.NonPublic.Arrange(fo, "DoAction", typeof(Foo), ArgExpr.IsAny<Object[]>()).MustBeCalled();
     
     
            fo.PublicAction(typeof(Foo));
            Mock.Assert(fo);
        }
    }

    I am sorry if I am missing something here. Let me know if you have any questions.

    Regards,
    Svetlozar
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items

     
  6. Gerard
    Gerard avatar
    4 posts
    Member since:
    Apr 2016

    Posted 13 Jul in reply to Svetlozar Link to this post

    Svetlozar,

    After looking again more closely, your original response had the answer I was looking for.

    Thank you for your help!

  7. Svetlozar
    Admin
    Svetlozar avatar
    271 posts

    Posted 14 Jul Link to this post

    Hi,

    I am glad you've managed to resolve the issue.

    Let us know if you have any other questions.

    Regards,
    Svetlozar
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top
DevCraft R3 2016 release webinar banner