如何使用参数化基础 class 为 subclass 编写单元测试
How do I write unit tests for subclass with parameterized base class
鉴于我在一个名为 GBase 的程序集中有一个 class,其构造函数采用 2 个参数,GBase 的子 class(称为 GDerived)采用相同的参数,如何我将它们分开,以便我可以对 subclass?
进行单元测试
在其他程序集中:
public class GBase
{
public GBase(ParamType1 param1, ParamType2 param2)
{
...
}
protected ParamType1 SomeProperty { get; set; }
// other stuff
}
在这个程序集中:
public class GDerived : GBase
{
public GDerived(ParamType1 param1, ParamType2 param2)
:base(param1, param2)
{
// new code
SomeProperty = newCalculatedValue;
// other stuff
}
// other stuff
}
原始 GBase class 是遗留代码,程序的一般结构也是如此——由于代码库大小(超过 10k 行),更改结构是不可能的 - none 直到最近才为其编写单元测试。
所以现在我想为 subclass 构造函数编写一个测试(使用 NUnit)来验证正确的属性是否填充了正确的值。请注意,测试 classes 与被测试的 classes 在同一个项目中。
[TestFixture]
public class GDerivedTests
{
[Test]
public void GDerivedConstructor_ValidParams_PropertiesSetCorrectly()
{
var newGDerived = new GDerived(parameter1, parameter2);
Assert.That(SomeProperty == parameter1;
}
}
这是我们必须处理的一个非常粗略的表示,除了在基础 class 中设置 属性 之外,还有一些情况我们需要测试。我什至不知道从哪里开始。我有 Michael Feathers 的书 Working Effectively with Legacy Code 但它似乎没有涵盖这种普遍的 "design pattern",在我们正在处理的代码中广泛使用。是因为它是如此简单,任何眨眼的 idjyot 都应该知道如何处理它,还是因为它是一种罕见的情况?不知何故,我也不认为是,但我可能是错的...
我想到的一种可能的方法是为基础 class 提取一个接口并模拟基础 class 构造函数 - 但我不确定如何做到这一点的细节。请注意,我们都是团队单元测试的相对新手,没有经验可以借鉴。不是编码新手,只是单元测试新手。
TIA,
戴夫
首先:保持简单!在您的示例中,您唯一可以测试的是 SomeProperty
。其他一切都在基础 class 中,您似乎不想测试,因此测试方法 GDerivedConstructor_ValidParams_PropertiesSetCorrectly()
没有意义。从长远来看,对其进行测试可能是明智的。
测试通常包含称为 AAA 的三个元素:安排、行动和断言。所以像这样写你的测试:
[Test]
public void GDerivedTestOfSomeProperty()
{
// arrange
ParamOfSomeProperty expected = ValueWeAreLookingFor; // this is something that you
// have in newCalculatedValue
// act
GDerived actual = new GDerived(
AnyValueThatMakesThisTestWork1, // maybe null?
AnyValueThatMakesThisTestWork2); // maybe null?
// assert
Assert.AreEqual(expected, actual.SomeProperty);
}
这就是开始。从这里走。您很快就会发现您得到了很多冗余代码,因此您可能想在一段时间后重新设计它。
模拟对于测试基础 class 或者当基础 class 对注入的对象做一些奇怪的事情时是有意义的。在这种情况下,传入模拟而不是真实对象。我个人会使用一个模拟框架来为您完成所有工作,您也可以使用它来测试基础 class 本身。一个著名的例子是 moq.
附带说明:如果将测试 classes 移到它自己的项目中,您会过得更好。出于各种原因不应发布测试代码,而且构建、测试和部署如果分开可能会更容易。
鉴于我在一个名为 GBase 的程序集中有一个 class,其构造函数采用 2 个参数,GBase 的子 class(称为 GDerived)采用相同的参数,如何我将它们分开,以便我可以对 subclass?
进行单元测试在其他程序集中:
public class GBase
{
public GBase(ParamType1 param1, ParamType2 param2)
{
...
}
protected ParamType1 SomeProperty { get; set; }
// other stuff
}
在这个程序集中:
public class GDerived : GBase
{
public GDerived(ParamType1 param1, ParamType2 param2)
:base(param1, param2)
{
// new code
SomeProperty = newCalculatedValue;
// other stuff
}
// other stuff
}
原始 GBase class 是遗留代码,程序的一般结构也是如此——由于代码库大小(超过 10k 行),更改结构是不可能的 - none 直到最近才为其编写单元测试。
所以现在我想为 subclass 构造函数编写一个测试(使用 NUnit)来验证正确的属性是否填充了正确的值。请注意,测试 classes 与被测试的 classes 在同一个项目中。
[TestFixture]
public class GDerivedTests
{
[Test]
public void GDerivedConstructor_ValidParams_PropertiesSetCorrectly()
{
var newGDerived = new GDerived(parameter1, parameter2);
Assert.That(SomeProperty == parameter1;
}
}
这是我们必须处理的一个非常粗略的表示,除了在基础 class 中设置 属性 之外,还有一些情况我们需要测试。我什至不知道从哪里开始。我有 Michael Feathers 的书 Working Effectively with Legacy Code 但它似乎没有涵盖这种普遍的 "design pattern",在我们正在处理的代码中广泛使用。是因为它是如此简单,任何眨眼的 idjyot 都应该知道如何处理它,还是因为它是一种罕见的情况?不知何故,我也不认为是,但我可能是错的...
我想到的一种可能的方法是为基础 class 提取一个接口并模拟基础 class 构造函数 - 但我不确定如何做到这一点的细节。请注意,我们都是团队单元测试的相对新手,没有经验可以借鉴。不是编码新手,只是单元测试新手。
TIA, 戴夫
首先:保持简单!在您的示例中,您唯一可以测试的是 SomeProperty
。其他一切都在基础 class 中,您似乎不想测试,因此测试方法 GDerivedConstructor_ValidParams_PropertiesSetCorrectly()
没有意义。从长远来看,对其进行测试可能是明智的。
测试通常包含称为 AAA 的三个元素:安排、行动和断言。所以像这样写你的测试:
[Test]
public void GDerivedTestOfSomeProperty()
{
// arrange
ParamOfSomeProperty expected = ValueWeAreLookingFor; // this is something that you
// have in newCalculatedValue
// act
GDerived actual = new GDerived(
AnyValueThatMakesThisTestWork1, // maybe null?
AnyValueThatMakesThisTestWork2); // maybe null?
// assert
Assert.AreEqual(expected, actual.SomeProperty);
}
这就是开始。从这里走。您很快就会发现您得到了很多冗余代码,因此您可能想在一段时间后重新设计它。
模拟对于测试基础 class 或者当基础 class 对注入的对象做一些奇怪的事情时是有意义的。在这种情况下,传入模拟而不是真实对象。我个人会使用一个模拟框架来为您完成所有工作,您也可以使用它来测试基础 class 本身。一个著名的例子是 moq.
附带说明:如果将测试 classes 移到它自己的项目中,您会过得更好。出于各种原因不应发布测试代码,而且构建、测试和部署如果分开可能会更容易。