AutoFixture:如何使用通用的测试数据集来生成不同的对象?
AutoFixture: How to use a common test data set for the generation of different objects?
我想测试一个自己编写的 XML 解析器,它接受一个 XML 字符串和 returns 它的模型表示。
T Parse(string content);
我遇到的问题是关于我测试的断言部分。因为每次我调用 Create<T>()
它都会生成新的随机数据,在那种情况下这不是我想要的。我需要一个可以按以下顺序使用的通用测试数据集:
a) 生成 XML 可以传递给我的解析器的字符串
b) 使用相同的测试数据集生成模型表示
c) 将 XML 解析器结果与生成的模型表示和 Assert.AreEqual()
进行比较
我遇到了 Freeze<T>()
方法,"sounds" 喜欢它可以满足我的目的。但是我不知道如何使用它。
所以问题是:如何使用通用的测试数据集来生成不同的对象?
这是我目前的方法和静态测试数据生成器class。
public static class TestDataGenerator
{
public static string GenerateSyntheticXmlTestData<T>(int minOid, int maxOid, int amount = 5)
{
var fixture = new Fixture()
{
RepeatCount = amount
};
fixture.Customizations.Add(new OidGenerator(minOid, maxOid));
fixture.Customizations.Add(new EnableAllProperties());
var testData = fixture.Create<T>();
var serializedXmlTestData = XmlSerializerHelper.Current.SerializeToXmlDocument(testData, Encoding.UTF8);
return serializedXmlTestData;
}
public static ICollection<T> GenerateSyntheticModelTestData<T>(int minOid, int maxOid, int amount = 1)
{
var fixture = new Fixture()
{
RepeatCount = 1
};
fixture.Customizations.Add(new OidGenerator(minOid, maxOid));
var testData = fixture.CreateMany<T>(amount).ToList();
return testData;
}
}
这就是我想测试解析器的方式。我希望它清楚我想要实现的目标。
[Fact]
public void ShouldParse()
{
// [...]
var xmlContent = TestDataGenerator.GenerateSyntheticXmlTestData<MyType>(minOid: 1, maxOid: 100, amount: 5);
// Here I would like to generate a model object using the same data
//
// var modelContent = new Fixture().Create<ModelType>();
var parsedContent = parser.Parse(xmlContent);
//parsedContent.Should().BeEquivalentTo(modelContet);
}
我不是 100% 确定这是否是您要找的东西,但也许可以选择为您的 XML-数据创建具有自定义类型的自定义夹具?
public class CustomFixture : Fixture
{
Customize<YourXmlType>(c => c.Without(f => f.XmlStringThatShouldNotBeGenerated));
Customize<YourXmlType>(c => c.Do(f => f.XmlStringThatShouldNotBeGenerated = "Your shared xml string"));
}
这也可以与 c.With
一起使用,而不是 Without 和 Do,但是我前段时间在一个项目中遇到了问题,上面的解决方案对我来说更可靠。
在测试解析器时,我经常发现从基于 属性 的测试手册 中获取一页是最简单的。许多对基于 属性 的测试有用的技术对 AutoFixture 也很有用。
在对解析逻辑进行基于 属性 的测试时,定义与解析器一起使用的序列化程序通常很有用。即,可以将给定模型转换为解析器解析的格式的函数。在这种情况下,它将是一个 XML 序列化程序。
指示 AutoFixture(或基于 属性 的测试库)创建 'model' 对象的有效实例,而不是指示它生成有效的 XML 字符串,通常要容易得多.
设置 AutoFixture 来执行此操作后,让它创建模型的实例,然后序列化模型,并让解析器解析序列化的模型。断言是解析模型应该等于输入模型。
Scott Wlaschin 使用 FsCheck 称此测试模式为 There and back again. You can also see an example of it on my blog。
使用 AutoFixture,它可能看起来像这样:
[Fact]
public void RoundTrippingWorks()
{
var fixture = new Fixture().Customize(/*...*/);
var model = fixture.Create<MyModel>();
string xml = MyXmlSerializer.Serialize(model);
MyModel actual = MyXmlParser.Parse(xml);
Assert.Equal(model, actual);
}
(我没试过编译,所以可能有错别字...)
我想测试一个自己编写的 XML 解析器,它接受一个 XML 字符串和 returns 它的模型表示。
T Parse(string content);
我遇到的问题是关于我测试的断言部分。因为每次我调用 Create<T>()
它都会生成新的随机数据,在那种情况下这不是我想要的。我需要一个可以按以下顺序使用的通用测试数据集:
a) 生成 XML 可以传递给我的解析器的字符串
b) 使用相同的测试数据集生成模型表示
c) 将 XML 解析器结果与生成的模型表示和 Assert.AreEqual()
我遇到了 Freeze<T>()
方法,"sounds" 喜欢它可以满足我的目的。但是我不知道如何使用它。
所以问题是:如何使用通用的测试数据集来生成不同的对象?
这是我目前的方法和静态测试数据生成器class。
public static class TestDataGenerator
{
public static string GenerateSyntheticXmlTestData<T>(int minOid, int maxOid, int amount = 5)
{
var fixture = new Fixture()
{
RepeatCount = amount
};
fixture.Customizations.Add(new OidGenerator(minOid, maxOid));
fixture.Customizations.Add(new EnableAllProperties());
var testData = fixture.Create<T>();
var serializedXmlTestData = XmlSerializerHelper.Current.SerializeToXmlDocument(testData, Encoding.UTF8);
return serializedXmlTestData;
}
public static ICollection<T> GenerateSyntheticModelTestData<T>(int minOid, int maxOid, int amount = 1)
{
var fixture = new Fixture()
{
RepeatCount = 1
};
fixture.Customizations.Add(new OidGenerator(minOid, maxOid));
var testData = fixture.CreateMany<T>(amount).ToList();
return testData;
}
}
这就是我想测试解析器的方式。我希望它清楚我想要实现的目标。
[Fact]
public void ShouldParse()
{
// [...]
var xmlContent = TestDataGenerator.GenerateSyntheticXmlTestData<MyType>(minOid: 1, maxOid: 100, amount: 5);
// Here I would like to generate a model object using the same data
//
// var modelContent = new Fixture().Create<ModelType>();
var parsedContent = parser.Parse(xmlContent);
//parsedContent.Should().BeEquivalentTo(modelContet);
}
我不是 100% 确定这是否是您要找的东西,但也许可以选择为您的 XML-数据创建具有自定义类型的自定义夹具?
public class CustomFixture : Fixture
{
Customize<YourXmlType>(c => c.Without(f => f.XmlStringThatShouldNotBeGenerated));
Customize<YourXmlType>(c => c.Do(f => f.XmlStringThatShouldNotBeGenerated = "Your shared xml string"));
}
这也可以与 c.With
一起使用,而不是 Without 和 Do,但是我前段时间在一个项目中遇到了问题,上面的解决方案对我来说更可靠。
在测试解析器时,我经常发现从基于 属性 的测试手册 中获取一页是最简单的。许多对基于 属性 的测试有用的技术对 AutoFixture 也很有用。
在对解析逻辑进行基于 属性 的测试时,定义与解析器一起使用的序列化程序通常很有用。即,可以将给定模型转换为解析器解析的格式的函数。在这种情况下,它将是一个 XML 序列化程序。
指示 AutoFixture(或基于 属性 的测试库)创建 'model' 对象的有效实例,而不是指示它生成有效的 XML 字符串,通常要容易得多.
设置 AutoFixture 来执行此操作后,让它创建模型的实例,然后序列化模型,并让解析器解析序列化的模型。断言是解析模型应该等于输入模型。
Scott Wlaschin 使用 FsCheck 称此测试模式为 There and back again. You can also see an example of it on my blog。
使用 AutoFixture,它可能看起来像这样:
[Fact]
public void RoundTrippingWorks()
{
var fixture = new Fixture().Customize(/*...*/);
var model = fixture.Create<MyModel>();
string xml = MyXmlSerializer.Serialize(model);
MyModel actual = MyXmlParser.Parse(xml);
Assert.Equal(model, actual);
}
(我没试过编译,所以可能有错别字...)