Using Moq, how can I check if all the properties of an object have been copied?

I have an interface with the CopyFrom () method that copies all properties from another object. I have a test that makes several calls to VerifyGet () to ensure that every property has been retrieved from the passed object, for example:

Thing target = new Thing(); IThing source = new Mock<IThing>(); target.CopyFrom(source.Object); source.VerifyGet(t => t.Foo); source.VerifyGet(t => t.Bar); 

I need a way to repeat the IThing properties, although make sure that each of them was copied automatically, so the test will fail if someone adds the property, but forgot to copy it. Is there a way to do this through Moq? I tried;

 foreach (var prop in typeof(IThing).GetProperties()) { source.VerifyGet(t => prop.Invoke(t, null)); } 

but this did not work, because the lambda was not an accessor of properties. I think there should be a way to create something through the Expression class, but I'm not familiar enough with LINQ to figure out what should be there.

+4
source share
2 answers

I don’t think that this is possible with Moq, but first of all you need to ask a question about whether your test is relevant. What do you really want to check here?

Is it important for the CopyFrom method to read any properties? He can definitely read all the properties without writing them to a new instance, so such an interaction-based test really proves nothing.

I assume that you really would like to verify that the properties of the target are equal to the properties of the source?

Assuming that the properties on IThing are writable, you can create a Stub with all the properties set using the SetupAllProperties method:

 var sourceStub = new Mock<IThing>(); sourceStub.SetupAllProperties(); sourceStub.Object.Bar = "Bar"; sourceStub.Object.Foo = "Foo"; 

Then you need to compare the target with the source to see if all the properties match. This can be done by implementing the Equal Test Equals method in a class that wraps the real target.

If you think this is too much work, you can check the AutoFixture Likeness Class, which gives you universal equality testing. This will allow you to continue the test as follows:

 var expectedResult = new Likeness<IThing>(sourceStub.Object); target.CopyFrom(sourceStub.Object); Assert.AreEqual(expectedResult, target); 

Likeness uses Reflection to simply iterate over all the public properties in the wrapped object and see if the compared object has the same values ​​for these properties.

+4
source
 /// <summary> /// Verifies that a property was read on the mock /// </summary> public static void VerifyGet<T>(this Mock<T> mockedObject, string propertyName) where T : class { var property = typeof(T).GetProperty(propertyName); if (property == null) throw new ArgumentException(string.Format("No property by the name '{0}' was found on '{1}'.", propertyName, typeof(T).Name)); // getPropFuncExpression = obj => obj.propertyName; var parameterExpression = Expression.Parameter(typeof(T), typeof(T).Name); var propertyExpression = Expression.Property(parameterExpression, property); var getPropFuncExpression = Expression.Lambda(propertyExpression, parameterExpression); var verifyGet = mockedObject.GetType().GetMethods().Single(m => m.Name == "VerifyGet" && m.GetParameters().Length == 1); verifyGet.MakeGenericMethod(property.PropertyType).Invoke(mockedObject, new object[] { getPropFuncExpression }); } 

You can add the above extension method so you can just call:

 foreach (var prop in typeof(IThing).GetProperties()) { source.VerifyGet(prop.Name); } 
+1
source

All Articles