2
Vote

Contract verifiers

description

As per comment on roadmap page:
+1 for contract verifiers. I needed to test all implementers of IEquatable<T> the other day, and ended up getting partial coverage via LINQing over reflection to pull out the types implementing it, then writing tests to verify each in a loop. This was so that I could get coverage for the R#-generated equality-members implementations. I'm left feeling a little dirty, as I've written tests that will not necessarily fail if I subsequently add members to the types that should participate in the calculations without regenerating the equality members... So perhaps a better thing would be if xunit.assert could be persuaded to use a custom equality method when comparing instances of types that don't implement IEquatable<TItself> such that it uses the same implementation as ReSharper would generate but using reflection to pull out the public properties to participate....? Wild idea. TypeResolvers.codeplex.com may assist here...?

comments

EmperorXLII wrote Jun 25, 2009 at 2:04 PM

If I understand your comment correctly, you have an auto-generated Equals implementation and you want to make sure that it takes into account all of the properties on the type? Here's how I'd go about it. (Note, this is just an outline, made as close to compilable code as memory allows, and does not include useful information like the name of the current property being tested in the assert.)

[Fact]
public void MyType_uses_all_properties_in_Equals( ) {
TestEqualsProperties( () => new MyType() );
}

private static void TestEqualsProperties( Func createInstance ) {
T first = new T();
T second = new T();
Assert.Equal( first, second );

var settableProperties = typeof(T).GetProperties( ).Where( p => p.IsSettable );
foreach( PropertyInfo property in settableProperties ) {
object currentValue = property.GetValue( first );
object newValue = TypeResolver.TypeCreator.GetCreators( property.PropertyType )
  .Select( creator => creator.CreateInstance( ) )
  .Where( value => !object.Equals( value, currentValue ) )
  .First( );
Assert.NotEqual( currentValue, newValue );

property.SetValue( first, newValue );
Assert.NotEqual( first, second );

property.SetValue( second, newValue );
Assert.Equal( first, second );
}
}

This creates two instances of the type to test and iterates through all the settable properties, setting each one two a new value in turn. If the Equals implementation does not use one of the properties, then the Assert.NotEqual call will fail. Also note that I specifically did not use [GenericTheory] with IEquatable, because there is no mechanism in TypeResolver to limit the types returned to your assembly (other than by referencing an interface only included in your assembly).

And by the way, it's http://typeresolver.codeplex.com/, not TypeResolverS ;)