Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The second invocation of a method with a Dictionary argument overwrites the dictionary passed in the previous invocation. #146

Closed
sandshadow opened this issue Dec 16, 2014 · 2 comments

Comments

@sandshadow
Copy link

using Moq;
using NUnit.Framework;
using System;
using System.Collections.Generic;

namespace Issue146Repro
{
    /* Issue: 
     * When a mocked method that takes a Dictionary argument is invoked a second time, the values that 
     * the dictionary contained in the first invocation are overwritten with the values from the 2nd invocation.
     */

    [TestFixture]
    public class Issue146ReproTests
    {
        static Mock<ISimpleInterface> mockedService;

        [SetUp]
        public void SetupMock()
        {
            mockedService = new Mock<ISimpleInterface>();
            mockedService.Setup(s => s.MethodWithDictionaryArg(It.IsAny < Dictionary<string, string>>()));
        }

        [TestCase]
        public void TestIssue146()
        {
            SimpleClass simpleClass = new SimpleClass(mockedService.Object);
            Dictionary<string, string> map = new Dictionary<string, string>()
            {
                { "FirstKey", "ValueForFirstKey"}
            };
            simpleClass.DoSomething(map);

            // Take a look at the InterceptionContext.ActualInvocations on mockedService. At this point, the arguments to the first invocation 
            // are just {[FirstKey, ValueForFirstKey]}. That causes this call to Verify to pass.
            mockedService.Verify(s => s.MethodWithDictionaryArg(
                It.Is<Dictionary<string, string>>(d => d.ContainsKey("SecondKey") && d["SecondKey"] == "ValueForSecondKey"))
                , Times.Never());

            map.Add("SecondKey", "ValueForSecondKey");
            simpleClass.DoSomething(map);

            // Take another look at the InterceptionContext.ActualInvocations. We now have two invocations (as expected), but the arguments 
            // to the first invocation now include {[SecondKey, ValueForSecondKey]} as well as {[FirstKey, ValueForFirstKey]}.
            // That causes this call to Verify to fail with "Expected invocation on the mock once, but was 2 times"
            mockedService.Verify(s => s.MethodWithDictionaryArg(
                It.Is<Dictionary<string, string>>(d => d.ContainsKey("SecondKey") && d["SecondKey"] == "ValueForSecondKey"))
                , Times.Once());
        }

        public class SimpleClass
        {
            ISimpleInterface simpleInterface;

            public SimpleClass(ISimpleInterface interfaceArg)
            {
                this.simpleInterface = interfaceArg;
            }

            public void DoSomething(Dictionary<string, string> map)
            {
                this.simpleInterface.MethodWithDictionaryArg(map);
            }

            public void MethodWithDictionaryArg(Dictionary<string, string> map)
            {
                Console.WriteLine();
            }
        }

        public interface ISimpleInterface
        {
            void MethodWithDictionaryArg(Dictionary<string, string> map);
        }
    }
}
@sandshadow
Copy link
Author

It seems to be tied to the same instance of the dictionary being used for the two invocations. If I switch the 2nd invocation to use a new dictionary, the test passes:

            //map.Add("SecondKey", "ValueForSecondKey");
            map = new Dictionary<string, string>()
            {
                { "FirstKey", "ValueForFirstKey" },
                { "SecondKey", "ValueForSecondKey" }
            };
            simpleClass.DoSomething(map);

But this still seems incorrect to me since we have only invoked the method once when the dictionary contained the 2nd key.

@kzu
Copy link
Member

kzu commented Dec 17, 2014

You are calling a method twice with the same dictionary instance. Moq is
not changing anything. Your code is adding another key to the same
dictionary. That's just how objects work.

On Tuesday, December 16, 2014, Eric Dettinger [email protected]
wrote:

It seems to be tied to the same instance of the dictionary being used for
the two invocations. If I switch the 2nd invocation to use a new
dictionary, the test passes:

        //map.Add("SecondKey", "ValueForSecondKey");
        map = new Dictionary<string, string>()
        {
            { "FirstKey", "ValueForFirstKey" },
            { "SecondKey", "ValueForSecondKey" }
        };
        simpleClass.DoSomething(map);

But this still seems incorrect to me since we have only invoked the method
once when the dictionary contained the 2nd key.

Reply to this email directly or view it on GitHub
#146 (comment).

/kzu from mobile

@kzu kzu closed this as completed Dec 17, 2014
@devlooped devlooped locked and limited conversation to collaborators Sep 8, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants