Scribe4net is also on codeplex feel free to suggest changes and open defects...
Introduction
Scrive4net is a simple serializer for test scenarios, in contrast to traditional serializers which are used for object persistance to HDD or over network connections, no thought was given to deseirialization back to the original object (as this was not the intention), the main concern here was human readability and full control over serialization.
The need it fills is getting an object into text form so it can be compared to the standard / preapproved object, or to approve it as the standard object.
- The output string is as human readable as can be, and comes with built in formatting.
- Output is deterministic = the same object will produce the same output string every time. (for string diffing)
- Produces a simple ToString value for primitive types (including string and date)
- Produces a xml / json representation of an object including all properties
- Opt in & opt out support
- Depth limitation support
- Handles List / Array & Dictionary properties (IEnumerable & IDictionary)
- Complience with standard xml & json formats is provided so deserialization into a wroking object model is easy.
- Supports serializing properties and fields of any object
- Full control over which types of members to serialize (public / nonPublic / static / instance)
Background
As software project have grown in size and complexity, many of them began to rely on multi tiered automatic testing for early dicovery of bugs and regressions, unit tests and integration tests are a big part of that, but they are time consuming and writing them is definitely not of the best loved things to code...
I have been looking for ways to shorten the time it takes to write tests, and came across the concept of comparing the object recieved to a standard object, preapproved as the correct answer (both in string form), this way can be used instead of checking the object's properties and verifying it's content by code, it is easy to understand and compare, there are many nice diff tools for the job, and you don't need to code the assertions by hand.
This approach can already make use of a nice framework called Approval Tests which speeds up comparing and approving the string representations of the situations, but i still thought there is still something missing: Getting the object into string form is still done manually, picking the right set of fields, and creating getString and ToString functions. What about complex objects like trees? getting those into string form takes a bit of work, and you have to do it all over again for each class.
So i started writing this little project, its a simple serializer written in c# with the json concept in mind: everything can be expressed using only dictionaries and lists, and an object is just a dictionary...
The main point is that you get full control over the output serialization, and that the output is readable, so that changes will really pop up when diffed.
Using the code
I kept the usage of this class as simple as can be, just a simple static call to the function:
string result = TestObjectSerializer.SerializeToString(yourObject, SerializationType.Xml);
When more control is needed you can pass an aditional settings object:
SerializationSettings settings = new SerializationSettings()
{
MaxDept = -1,
IncludeFields = true,
FieldInclusion = BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic
};
string result = TestObjectSerializer.SerializeToString(yourObject, SerializationType.Xml, settings);
The SerializationSettings object contains the following properties:
- MaxDept lets you control the depth which the serializer will reach in the object graph before stopping.
- Include fields allows you to include fields (in addition to properties)
- FieldInclusion is a BindingFlags enum, which allows full control over which types of fields to include
- PropertyInclusion is a BindingFlags enum, which allows full control over which types of properties to serialize.
- OptIn is a boolean which switches between opt in and out modes (default is OptOut, where all properties are included, unless an attribute is set to exclude them).
To Exclude properties you can use the [TestSerializerOptOut
] attribute:
[TestSerializerOptOut]
string YourProperty {get;set;}
To inlude only explicitly included properties you can use the [TestSerializerOptIn
] attribute while passing the OptIn=true setting in the settings object (this is false by default):
[TestSerializerOptIn]
string YourProperty {get;set;}
Serialization Depth can be controlled by changing the MaxDept setting (-1 is unlimited, and is the default)
SerializationSettings settings = new SerializationSettings()
{
MaxDept = 3,
};
So now objects can be compared as simply and easily as comparing integers and strings, asserting the correctness of a complex situation now takes two lines of code:
string result = TestObjectSerializer.SerializeToString(primitive1, SerializationType.Xml);
Approvals.Verify(result);
The second line uses Approval tests, but it can just as easily be Assert.Equals(strExpected,strReceived).
Conclusions
I hope this will cut some test writing time for everyone... tell me what you think !