Skip to content

Commit

Permalink
Add XML and C# serialization methods to ITestOutputHelper
Browse files Browse the repository at this point in the history
This update introduces additional methods to ITestOutputHelper: WriteCSharp for outputting objects as C# code, and WriteXml for XML serialization. It incorporates various classes and test cases to support the new functionality. Projects and namespace allocations were also updated where necessary.
  • Loading branch information
frankhaugen committed Jan 3, 2024
1 parent 3c72455 commit 11b1b90
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<RootNamespace>Xunit</RootNamespace>
<RootNamespace>Xunit.Abstractions</RootNamespace>
<Description>Extends ITestOutputHelper to allow output of a generic type using a serializer.</Description>
<PackageTags>test, xunit, output, helper, serializer, json, console</PackageTags>
<PackageTags>test, testing, extensions, xunit, output, helper, serializer, json, xml, csharp, dump, var, dumpvar, vardump, xmlserializer, jsonserializer, testoutputhelper, testoutput, outputhelper, ITestOutputHelper, abstractions, xunit.abstractions, xunit.abstractions.extensions, xunit.extensions.ordering</PackageTags>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="VarDump" Version="0.2.11" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
<PackageReference Include="Xunit.Extensions.Ordering" Version="1.4.5" />
</ItemGroup>
Expand Down
53 changes: 53 additions & 0 deletions Frank.Testing.TestOutputExtensions/TestOutputCSharpExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.ComponentModel;

using FluentAssertions;

using VarDump;
using VarDump.Visitor;

namespace Xunit.Abstractions;

public static class TestOutputCSharpExtensions
{
/// <summary>
/// Writes the provided source object as C# code to the test output.
/// </summary>
/// <remarks>
/// The C# code is written using the <see cref="CSharpDumper"/>
/// </remarks>
/// <example>
/// <code>
/// var testPerson = new Frank.Testing.Tests.TestPerson
/// {
/// Name = "John Doe",
/// Age = 30,
/// Address = new Frank.Testing.Tests.TestAddress
/// {
/// City = "Main City",
/// ZipCode = 18846
/// }
/// };
/// </code>
/// </example>
/// <typeparam name="T">The type of the source object.</typeparam>
/// <param name="outputHelper">The test output helper.</param>
/// <param name="source">The source object to be written as C# code.</param>
/// <param name="dumpOptions">The optional dump options to control the formatting of the C# code.</param>
public static void WriteCSharp<T>(this ITestOutputHelper outputHelper, T source, DumpOptions? dumpOptions = null)
{
var options = dumpOptions ?? DumpOptions;
var dumper = new CSharpDumper(options);
outputHelper.WriteLine(dumper.Dump(source));
}

private static DumpOptions DumpOptions => new DumpOptions()
{
IgnoreNullValues = true,
DateKind = DateKind.ConvertToUtc,
DateTimeInstantiation = DateTimeInstantiation.Parse,
UseTypeFullName = true,
GenerateVariableInitializer = true,
SortDirection = ListSortDirection.Ascending,
MaxDepth = 64,
};
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using System.Text.Json;
using System.Text.Json.Serialization;

using Xunit.Abstractions;
namespace Xunit.Abstractions;

namespace Xunit;

public static class TestOutputExtensions
public static class TestOutputJsonExtensions
{
/// <summary>
/// Writes the specified object's string representation followed by the current line terminator to the output.
Expand Down
29 changes: 29 additions & 0 deletions Frank.Testing.TestOutputExtensions/TestOutputXmlExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace Xunit.Abstractions;

public static class TestOutputXmlExtensions
{
public static void WriteXml<T>(this ITestOutputHelper outputHelper, T source, XmlWriterSettings? xmlWriterSettings = null)
{
var settings = xmlWriterSettings ?? XmlWriterSettings;

using var textWriter = new StringWriter();
using var xmlWriter = XmlWriter.Create(textWriter, settings);
var xmlSerializer = new XmlSerializerFactory().CreateSerializer(typeof(T));
xmlSerializer.Serialize(xmlWriter, source);
outputHelper.WriteLine(textWriter.ToString());
}

private static XmlWriterSettings XmlWriterSettings => new()
{
Indent = true,
IndentChars = new string(' ', 4),
NewLineChars = "\n",
NewLineHandling = NewLineHandling.Replace,
OmitXmlDeclaration = false,
Encoding = new UTF8Encoding(false),
};
}
2 changes: 2 additions & 0 deletions Frank.Testing.Tests/Frank.Testing.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.6.4" />
Expand All @@ -25,6 +26,7 @@

<ItemGroup>
<ProjectReference Include="..\Frank.Testing.Logging\Frank.Testing.Logging.csproj" />
<ProjectReference Include="..\Frank.Testing.TestOutputExtensions\Frank.Testing.TestOutputExtensions.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@

namespace Frank.Testing.Tests;

public class UnitTest1
public class TestLoggingTests
{
private readonly ITestOutputHelper _outputHelper;

public UnitTest1(ITestOutputHelper outputHelper)
public TestLoggingTests(ITestOutputHelper outputHelper)
{
_outputHelper = outputHelper;
}
Expand Down
17 changes: 17 additions & 0 deletions Frank.Testing.Tests/TestOutputCSharpExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using JetBrains.Annotations;

using Xunit.Abstractions;

namespace Frank.Testing.Tests;

[TestSubject(typeof(TestOutputCSharpExtensions))]
public class TestOutputCSharpExtensionsTests(ITestOutputHelper outputHelper)
{
[Fact]
public void WriteCSharp_ShouldWriteCSharpOutput_WhenSourceIsSimpleObject()
{
var source = new TestPerson { Name = "John Doe", Age = 30 };

outputHelper.WriteCSharp(source);
}
}
2 changes: 1 addition & 1 deletion Frank.Testing.Tests/TestOutputExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Frank.Testing.Tests;

[TestSubject(typeof(TestOutputExtensions))]
[TestSubject(typeof(TestOutputJsonExtensions))]
public class TestOutputExtensionsTests
{
private readonly ITestOutputHelper _outputHelper;
Expand Down
40 changes: 40 additions & 0 deletions Frank.Testing.Tests/TestOutputXmlExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using JetBrains.Annotations;

using Xunit.Abstractions;

namespace Frank.Testing.Tests;

[TestSubject(typeof(TestOutputXmlExtensions))]
public class TestOutputXmlExtensionsTests(ITestOutputHelper outputHelper)
{
[Fact]
public void WriteXml_ShouldWriteXmlOutput_WhenSourceIsSimpleObject()
{
var source = new TestPerson { Name = "John Doe", Age = 30 };

outputHelper.WriteXml(source);
}

[Fact]
public void WriteXml_ShouldWriteXmlOutput_WhenSourceIsNestedObject()
{
var source = new TestPerson() { Name = "John Doe", Age = 30, Address = new TestAddress() { City = "Main City", ZipCode = 18846 } };
outputHelper.WriteXml(source);
}

[Fact]
public void WriteXml_ShouldHandleEmptyObjects()
{
var source = new TestPerson();

outputHelper.WriteXml(source);
}

[Fact]
public void WriteXml_ShouldHandleNullObjects()
{
object? source = null;

outputHelper.WriteXml(source);
}
}
8 changes: 8 additions & 0 deletions Frank.Testing.Tests/TestingInfrastructure/TestAddress.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Frank.Testing.Tests;

public class TestAddress
{
public string City { get; set; }

Check warning on line 5 in Frank.Testing.Tests/TestingInfrastructure/TestAddress.cs

View workflow job for this annotation

GitHub Actions / Merge Job / Publish Preview Job

Non-nullable property 'City' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 5 in Frank.Testing.Tests/TestingInfrastructure/TestAddress.cs

View workflow job for this annotation

GitHub Actions / Release Job / Release Job

Non-nullable property 'City' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

public int ZipCode { get; set; }
}
9 changes: 9 additions & 0 deletions Frank.Testing.Tests/TestingInfrastructure/TestPerson.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Frank.Testing.Tests;

public class TestPerson
{
public string Name { get; set; }

Check warning on line 5 in Frank.Testing.Tests/TestingInfrastructure/TestPerson.cs

View workflow job for this annotation

GitHub Actions / Merge Job / Publish Preview Job

Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 5 in Frank.Testing.Tests/TestingInfrastructure/TestPerson.cs

View workflow job for this annotation

GitHub Actions / Release Job / Release Job

Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public int Age { get; set; }

public TestAddress? Address { get; set; }
}
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,20 @@ public class MyTestClass
[Fact]
public void MyTestMethod()
{
_outputHelper.WriteLine(new { MyProperty = "MyValue" });
_outputHelper.WriteLine(new { MyProperty = "MyValue" }); // Writes to test output as JSON: {"MyProperty":"MyValue"}
_outputHelper.WriteJson(new { MyProperty = "MyValue" }); // Writes to test output as JSON: {"MyProperty":"MyValue"}
}

[Fact]
public void MyTestMethod2()
{
_outputHelper.WriteCSharp(new { MyProperty = "MyValue" }); // Writes to test output as C#: var anonymousType = new { MyProperty = "MyValue" };
}

[Fact]
public void MyTestMethod3()
{
_outputHelper.WriteXml(new MyClass() { Name = "MyName" }); // Writes to test output as XML: <MyClass><Name>MyName</Name></MyClass>
}
}
```
Expand Down

0 comments on commit 11b1b90

Please sign in to comment.