如何编写一个处理不同类型的单元测试?
How to write one unit test that handles different types?
我正在为我的 discord 机器人编写测试(使用 XUnit),我想知道是否可以用一个测试替换我的测试。如果是这样,我该怎么做?
到目前为止,我为我的 Unity class(它是 Unity Container、DI 框架的包装器)编写了 4 个单元测试。这些测试按预期工作,但每次我向容器添加新类型时添加新测试似乎并不正确。我查看了类似问题的答案,但解决方案要么很复杂,要么对我的情况没有用。
我正在测试的来自 Unity class 的方法:
public static T Resolve<T>()
{
return Container.Resolve<T>();
}
它returns来自Unity容器的相应类型的实例。
测试:
[Fact]
public void ResolveIDataStorage_ShouldWork()
{
var storage1 = Unity.Resolve<IDataStorage>();
var storage2 = Unity.Resolve<IDataStorage>();
Assert.NotNull(storage1);
Assert.NotNull(storage2);
Assert.Same(storage1, storage2);
}
[Fact]
public void ResolveILogger_ShouldWork()
{
var logger1 = Unity.Resolve<ILogger>();
var logger2 = Unity.Resolve<ILogger>();
Assert.NotNull(logger1);
Assert.NotNull(logger2);
Assert.Same(logger1, logger2);
}
[Fact]
public void ResolveDiscordSocketClient_ShouldWork()
{
var client1 = Unity.Resolve<DiscordSocketClient>();
var client2 = Unity.Resolve<DiscordSocketClient>();
Assert.NotNull(client1);
Assert.NotNull(client2);
Assert.Same(client1, client2);
}
[Fact]
public void ResolveConnection_ShouldWork()
{
var con1 = Unity.Resolve<Connection>();
var con2 = Unity.Resolve<Connection>();
Assert.NotNull(con1);
Assert.NotNull(con2);
Assert.Same(con1, con2);
}
在每个测试中,我解析了一些类型并断言两个对象不为空并且它们应该是同一个实例。基本上,这些断言应该适用于任何类型(或一组特定类型,可以作为 [Theory] 测试的参数),因此,为了避免复制粘贴,进行一次测试将非常方便。
使用反射创建一个需要解析的类型的泛型方法并调用它。
从那里断言预期的行为。
使用内联数据,您现在可以重复测试而无需重复代码。
以下示例基于已提供的代码。
[Theory]
[InlineData(typeof(IDataStorage))]
[InlineData(typeof(ILogger))]
[InlineData(typeof(DiscordSocketClient))]
[InlineData(typeof(Connection))]
public void Resolve_Singleton_Services_ShouldWork(Type type) {
//Arrange
var unityType = typeof(Unity);
var resolve = unityType.GetMethod("Resolve", BindingFlags.Static| BindingFlags.Public);
var genericResolve = resolve?.MakeGenericMethod(type);
//Act
var instance1 = genericResolve?.Invoke(null, null); // Unity.Resolve<type>()
var instance2 = genericResolve?.Invoke(null, null); // Unity.Resolve<type>()
//Assert
Assert.NotNull(instance1);
Assert.NotNull(instance2);
Assert.Same(instance1, instance2);
}
测试的安排部分假定容器的每个配置都已被调用。
如果您的目标只是让一个测试对您要测试的每种类型都遵循相同的模式,您可以将测试提取到它自己的通用方法中,然后在单个测试中为每种类型调用它:
[Fact]
public void Resolve_ShouldWork()
{
AssertResolvedTypesAreSame<IDataStorage>();
AssertResolvedTypesAreSame<ILogger>();
AssertResolvedTypesAreSame<DiscordSocketClient>();
AssertResolvedTypesAreSame<Connection>();
}
private void AssertResolvedTypesAreSame<T>()
{
var t1 = Unity.Resolve<T>();
var t2 = Unity.Resolve<T>();
Assert.NotNull(t1);
Assert.NotNull(t2);
Assert.Same(t1, t2);
}
我正在为我的 discord 机器人编写测试(使用 XUnit),我想知道是否可以用一个测试替换我的测试。如果是这样,我该怎么做?
到目前为止,我为我的 Unity class(它是 Unity Container、DI 框架的包装器)编写了 4 个单元测试。这些测试按预期工作,但每次我向容器添加新类型时添加新测试似乎并不正确。我查看了类似问题的答案,但解决方案要么很复杂,要么对我的情况没有用。
我正在测试的来自 Unity class 的方法:
public static T Resolve<T>()
{
return Container.Resolve<T>();
}
它returns来自Unity容器的相应类型的实例。
测试:
[Fact]
public void ResolveIDataStorage_ShouldWork()
{
var storage1 = Unity.Resolve<IDataStorage>();
var storage2 = Unity.Resolve<IDataStorage>();
Assert.NotNull(storage1);
Assert.NotNull(storage2);
Assert.Same(storage1, storage2);
}
[Fact]
public void ResolveILogger_ShouldWork()
{
var logger1 = Unity.Resolve<ILogger>();
var logger2 = Unity.Resolve<ILogger>();
Assert.NotNull(logger1);
Assert.NotNull(logger2);
Assert.Same(logger1, logger2);
}
[Fact]
public void ResolveDiscordSocketClient_ShouldWork()
{
var client1 = Unity.Resolve<DiscordSocketClient>();
var client2 = Unity.Resolve<DiscordSocketClient>();
Assert.NotNull(client1);
Assert.NotNull(client2);
Assert.Same(client1, client2);
}
[Fact]
public void ResolveConnection_ShouldWork()
{
var con1 = Unity.Resolve<Connection>();
var con2 = Unity.Resolve<Connection>();
Assert.NotNull(con1);
Assert.NotNull(con2);
Assert.Same(con1, con2);
}
在每个测试中,我解析了一些类型并断言两个对象不为空并且它们应该是同一个实例。基本上,这些断言应该适用于任何类型(或一组特定类型,可以作为 [Theory] 测试的参数),因此,为了避免复制粘贴,进行一次测试将非常方便。
使用反射创建一个需要解析的类型的泛型方法并调用它。
从那里断言预期的行为。
使用内联数据,您现在可以重复测试而无需重复代码。
以下示例基于已提供的代码。
[Theory]
[InlineData(typeof(IDataStorage))]
[InlineData(typeof(ILogger))]
[InlineData(typeof(DiscordSocketClient))]
[InlineData(typeof(Connection))]
public void Resolve_Singleton_Services_ShouldWork(Type type) {
//Arrange
var unityType = typeof(Unity);
var resolve = unityType.GetMethod("Resolve", BindingFlags.Static| BindingFlags.Public);
var genericResolve = resolve?.MakeGenericMethod(type);
//Act
var instance1 = genericResolve?.Invoke(null, null); // Unity.Resolve<type>()
var instance2 = genericResolve?.Invoke(null, null); // Unity.Resolve<type>()
//Assert
Assert.NotNull(instance1);
Assert.NotNull(instance2);
Assert.Same(instance1, instance2);
}
测试的安排部分假定容器的每个配置都已被调用。
如果您的目标只是让一个测试对您要测试的每种类型都遵循相同的模式,您可以将测试提取到它自己的通用方法中,然后在单个测试中为每种类型调用它:
[Fact]
public void Resolve_ShouldWork()
{
AssertResolvedTypesAreSame<IDataStorage>();
AssertResolvedTypesAreSame<ILogger>();
AssertResolvedTypesAreSame<DiscordSocketClient>();
AssertResolvedTypesAreSame<Connection>();
}
private void AssertResolvedTypesAreSame<T>()
{
var t1 = Unity.Resolve<T>();
var t2 = Unity.Resolve<T>();
Assert.NotNull(t1);
Assert.NotNull(t2);
Assert.Same(t1, t2);
}