Using Moq can you verify a method call with an anonymous type?

前端 未结 3 1837
萌比男神i
萌比男神i 2021-02-18 17:50

I\'m trying to verify a method call using Moq, but I can\'t quite get the syntax right. Currently I\'ve go this as my verify:

repository.Verify(x => x.Execute         


        
相关标签:
3条回答
  • 2021-02-18 18:21

    One option is to "verify" it in a Callback. Obviously this needs to be done at Setup time, e.g.:

    aMock.Setup(x => x.Method(It.IsAny<object>())).Callback<object>(
      (p1) =>
        {
          dynamic o = p1;
          Assert.That(o.Name, Is.EqualTo("Bilbo"));
        });
    
    0 讨论(0)
  • 2021-02-18 18:35

    None of the answers are great when your test assembly is different than the system under test's assembly (really common). Here's my solution that uses Json serialization and then string comparison.

    Test Helper Function:

    using Newtonsoft.Json;
    
    public static class VerifyHelper
    {
        public static bool AreEqualObjects(object expected, object actual)
        {
            var expectedJson = JsonConvert.SerializeObject(expected);
            var actualJson = JsonConvert.SerializeObject(actual);
    
            return expectedJson == actualJson;
        }
    }
    

    Example System Under Test:

    public void DoWork(string input)
    {
         var obj = new { Prop1 = input };
         dependency.SomeDependencyFunction(obj);
    }
    

    Example Unit Test:

    var expectedObject = new { Prop1 = "foo" };
    
    sut.DoWork("foo");
    dependency.Verify(x => x.SomeDependencyFunction(It.Is<object>(y => VerifyHelper.AreEqualObjects(expectedObject, y))), Times.Once());
    

    This solution is really simple, and I think makes the unit test easier to understand as opposed to the other answers in this thread. However, because it using simple string comparison, the test's anonymous object has to be setup exactly the same as the system under test's anonymous object. Ergo, let's say you only cared to verify the value of a single property, but your system under test sets additional properties on the anonymous object, your unit test will need to set all those other properties (and in the same exact order) for the helper function to return true.

    0 讨论(0)
  • 2021-02-18 18:39

    This Passes

            public class Class1
        {
            private Class2 _Class2;
            public Class1(Class2 class2)
            {
                _Class2 = class2;
            }
    
            public void DoSomething(string s)
            {
                _Class2.ExecuteNonQuery(s, new { fid = 123,  inputStr = "000456" });
            }
        }
    
        public class Class2
        {
            public virtual void ExecuteNonQuery(string s, object o)
            {
            }
        }
    
        /// <summary>
        ///A test for ExecuteNonQuery
        ///</summary>
        [TestMethod()]
        public void ExecuteNonQueryTest()
        {
            string testString = "Hello";
            var Class2Stub = new Mock<Class2>();
            Class1 target = new Class1(Class2Stub.Object);
            target.DoSomething(testString);
            Class2Stub.Verify(x => x.ExecuteNonQuery(testString, It.Is<object>(o => o.Equals(new { fid = 123, inputStr = "000456" }))), Times.Once());
        }
    

    Update

    That is strange, it doesn't work in different assemblies. Someone can give us the long definition about why the object.equals from different assemblies behaves differently, but for different assemblies this will work, any variance in the object values will return a different hash code.

            Class2Stub.Verify(x => x.ExecuteNonQuery(testString, It.Is<object>(o => o.GetHashCode() == (new { fid = 123, inputStr = "000456" }).GetHashCode())), Times.Once());
    
    0 讨论(0)
提交回复
热议问题