简体   繁体   中英

Using Moq `It.Is` to verify constructor parameter / object with private field

Very simple example:

public class Test
{
     private int _field;

   public Test(int field)
   {
     _field = field;
   }
}

Now I want to check if method was invoked with parameter of type Test, that has constructor parameter equals to 5

_mock.Verify(x => x.Method(It.Is<Test>(constructor parameter equal to 5)));

If I understand correctly, you have a SUT ( SystemUnderTest , below)which invokes a dependency ( IDependency ) which you have mocked with an object of a class ( Test ) which doesn't expose a public getter property. As it stands, you would need to use a hack like reflection to check the private value, eg:

  public static TReturn GetPrivateField<TIn,TReturn>(TIn instance, 
                                                     string fieldName)
  {
     var fieldInfo = typeof(TIn).GetField(fieldName, BindingFlags.NonPublic | 
                             BindingFlags.Instance);
     return (fieldInfo != null)
               ? (TReturn)fieldInfo.GetValue(instance)
               : default(TReturn);
  }

  [Test]
  public void EnsureMethod()
  {
     var mock = new Mock<IDependency>();
     var sut = new SystemUnderTest(mock.Object);
     sut.DoSomethingGoodWithTest();

     mock.Verify(x => x.Method(It.Is<Test>(
                     t => GetPrivateField<Test, int>(t, "_field") == 5)));
  }

Obviously this is far from ideal, and if possible, the approach could be reconsidered:

If you are not in a position to change the access visibility to Test._field eg with a public getter, but are able to change the design of the class being tested, an alternative would be to use an injectible factory to create Test classes, eg with a method like IFactory.Create(int x) . This way you could mock the factory during testing, and then intercept the Create call and verify that the SUT was indeed creating the Test object with the required construction parameters.

In stead of testing the constructor you should somehow test if that property was set with correct value. See if you can expose it either with a method or property or any other way.

If you do not have access to that class to expose the property you have to see how it's being used, ie you look for the side-effects of this being initialized with 5 or 10 or whatever.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM