Xunit and dynamic

Working with XML serialization, I need to create object with several public properties taken from complex “parent” object, and its class is created on the fly via reflection. Full code is accessible on GitHub Blog repository.

The following MSDN’s topic contains an example of the creating dynamic class with public property. Let me list sample code that creates object with two properties: Name and Count.

public class ObjectFactory
{
	public static string[] PropertyNames = new[] { "Name", "Count" };
	public static Type[] PropertyTypes = new[] { typeof(string), typeof(int) };

	private readonly ModuleBuilder _moduleBuilder = null;

	public ObjectFactory()
	{
		var assemblyName = new AssemblyName() { Name = "LiteObjectTypes" };
		_moduleBuilder = Thread.GetDomain()
			.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run)
			.DefineDynamicModule(assemblyName.Name);
	}

	public object GetObject()
	{
		const string className = "LiteObject";
		var typeBuilder = _moduleBuilder.DefineType(className,
			TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable);

		for (var pos = 0; pos < PropertyNames.Length; pos++)
		{
			// create private field and init it by default value from DefaultValue attribute
			var fieldName = $"_{PropertyNames[pos].ToLower()[0]}{PropertyNames[pos].Substring(1)}";
			var fieldBuilder = typeBuilder.DefineField(fieldName, PropertyTypes[pos],
										FieldAttributes.Private);

			var propertyBuilder = typeBuilder.DefineProperty(PropertyNames[pos],
										PropertyAttributes.HasDefault,
										PropertyTypes[pos], null);

			// the property set and property get methods require a special set of attributes.
			const MethodAttributes accessorAttributes =
				MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;

			// define the "get" accessor method for CustomerName.
			var getterMethod = typeBuilder.DefineMethod($"get_{PropertyNames[pos]}",
									accessorAttributes,
									PropertyTypes[pos],
									Type.EmptyTypes);

			var getterMethodIL = getterMethod.GetILGenerator();

			getterMethodIL.Emit(OpCodes.Ldarg_0);
			getterMethodIL.Emit(OpCodes.Ldfld, fieldBuilder);
			getterMethodIL.Emit(OpCodes.Ret);

			// Define the "set" accessor method for CustomerName.
			var setterMethod = typeBuilder.DefineMethod($"set_{PropertyNames[pos]}",
									accessorAttributes,
									null,
									new Type[] { PropertyTypes[pos] });

			var setterMethodIL = setterMethod.GetILGenerator();

			setterMethodIL.Emit(OpCodes.Ldarg_0);
			setterMethodIL.Emit(OpCodes.Ldarg_1);
			setterMethodIL.Emit(OpCodes.Stfld, fieldBuilder);
			setterMethodIL.Emit(OpCodes.Ret);

			// Last, we must map the two methods created above to our PropertyBuilder to 
			// their corresponding behaviors, "get" and "set" respectively. 
			propertyBuilder.SetGetMethod(getterMethod);
			propertyBuilder.SetSetMethod(setterMethod);
		}

		var liteObjectType = typeBuilder.CreateType();
		if (liteObjectType == null)
			return null;

		return Activator.CreateInstance(liteObjectType);
	}
}

This code should be covered by unit tests. We need check the following cases: method returns not-null object with exactly two properties. The main issue that the type of constructed object is not defined during compile time. We use Xunit library, and let’s show two different approaches: the using dynamic type and TypeDescriptor class.

The first test takes the collection of properties via TypeDescritor type and checks whether properties with expected name and type exists.

[Fact]
public void GetObject_Should_ReturnObjectWithTwoProperties()
{
	object liteObject = null;
	var exception = Record.Exception(() => liteObject = (new ObjectFactory()).GetObject());

	// check correct properties
	Assert.Null(exception);
	Assert.NotNull(liteObject);

	var propertyInfos = TypeDescriptor.GetProperties(liteObject.GetType());
	Assert.Equal(propertyInfos.Count, ObjectFactory.PropertyNames.Length);

	for (var pos = 0; pos < ObjectFactory.PropertyNames.Length; pos++)
	{
		var property = propertyInfos[ObjectFactory.PropertyNames[pos]];
		Assert.NotNull(property);
		Assert.Equal(property.PropertyType, ObjectFactory.PropertyTypes[pos]);
	}
}

The second test casts returned object to dynamic type and checks two expected properties and one wrong property. It tries to read the value of expected and wrong properties and checks these operations against exception. Let me note, that one of the disadvantages of the using dynamic that it is slow, but I guess for the testing it is ok.

[Fact]
public void GetObject_Should_ReturnDynamicWithTwoProperties()
{
	dynamic liteObject = null;
	var exception = Record.Exception(() => liteObject = (new ObjectFactory()).GetObject());

	Assert.Null(exception);
	Assert.NotNull(liteObject);

	// check correct properties
	exception = Record.Exception(() =>
	{
		var name = liteObject.Name;
		Assert.Equal(name, null);
	});
	Assert.Null(exception);

	exception = Record.Exception(() =>
	{
		var count = liteObject.Count;
		Assert.Equal(count, new int());
	});
	Assert.Null(exception);

	// check wrong property
	exception = Record.Exception(() =>
	{
		var wrong = liteObject.Wrong;
		Assert.NotNull(wrong);
	});
	Assert.NotNull(exception);
	Assert.Equal(exception.Message, "'LiteObject' does not contain a definition for 'Wrong'");
}

Now let us to add methods that assign values to properties of created object:

public object GetObjectViaReflection(string name, int count)
{
	var liteObject = GetObject();
	if (liteObject == null)
		return null;

	var values = new object[] { name, count };

	var propertyInfos = TypeDescriptor.GetProperties(liteObject.GetType());
	for (var pos = 0; pos < PropertyNames.Length; pos++)
	{
		var property = propertyInfos[ObjectFactory.PropertyNames[pos]];
		property?.SetValue(liteObject, values[pos]);
	}

	return liteObject;
}

public object GetObjectViaDynamic(string name, int count)
{
	dynamic liteObject = GetObject();
	if (liteObject == null)
		return null;

	liteObject.Name = name;
	liteObject.Count = count;

	return liteObject;
}

The following tests check that property values of constructed object are assigned correctly. As above, they are written in different approaches.

[Fact]
public void GetObject_Should_AssignValuesViaReflection()
{
	const string name = "TestName1";
	const int count = 10;

	object liteObject = null;
	var exception = Record.Exception(() => liteObject = (new ObjectFactory()).GetObjectViaReflection(name, count));

	// check correct properties
	Assert.Null(exception);
	Assert.NotNull(liteObject);

	var propertyInfos = TypeDescriptor.GetProperties(liteObject.GetType());
	var values = new object[] { name, count };
	for (var pos = 0; pos < ObjectFactory.PropertyNames.Length; pos++)
	{
		var property = propertyInfos[ObjectFactory.PropertyNames[pos]];
		Assert.NotNull(property);
		Assert.Equal(property.GetValue(liteObject), values[pos]);
	}
}

[Fact]
public void GetObject_Should_AssignValuesViaDynamic()
{
	const string name = "TestName2";
	const int count = 20;

	dynamic liteObject = null;
	var exception = Record.Exception(() => liteObject = (new ObjectFactory()).GetObjectViaDynamic(name, count));

	// check correct properties
	Assert.Null(exception);
	Assert.NotNull(liteObject);
	Assert.Equal(liteObject.Name, name);
	Assert.Equal(liteObject.Count, count);
}

All tests are working well and cover necessary test cases. As for my opinion, both approaches could be used together that allows choose shorter and more elegant code for each test case.


1. All used IP-addresses, names of servers, workstations, domains, are fictional and are used exclusively as a demonstration only.
2. Information is provided «AS IS».

One thought on “Xunit and dynamic

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.