如何在单元测试中使用全局变量?
How do I use a global variable in unit testing?
我也需要在其他测试中的第一个测试中初始化的对象。
为了防止代码重复,我想将我在第一个测试中创建的对象保存在一个全局变量中。这就是我所做的:
namespace Project.WebUIV2.Tests {
[TestClass]
public class FilmSelectieControllerTests {
private FilmSelectieController controller;
[TestMethod]
public void CanInitializeController() {
Mock<IRepository<Voorstelling>> mockIRepository1 = new Mock<IRepository<Voorstelling>>();
Mock<IRepository<Film>> mockIRepository2 = new Mock<IRepository<Film>>();
Mock<IRepository<Zaal>> mockIRepository3 = new Mock<IRepository<Zaal>>();
Film film = new Film { titel = "Film" };
mockIRepository2.Setup(m => m.Add(film));
var repository1 = mockIRepository1.Object;
var repository2 = mockIRepository2.Object;
var repository3 = mockIRepository3.Object;
var controller = new FilmSelectieController(repository1, repository2, repository3);
Assert.IsNotNull(controller);
Assert.IsInstanceOfType(controller, typeof(FilmSelectieController));
this.controller = controller;
}
[TestMethod]
public void IsCreated() {
Assert.IsInstanceOfType(controller, typeof(FilmSelectieController));
}
}
}
测试方法 CanInitializeController() 成功,而 isCreated() 失败。
在第一个测试中,我创建了 FilmSelectieController 对象。
如何在接下来的测试中使用该对象?
感谢 Anthony Pegram
解法:
..*/
private Controller controller;
[TestInitialize]
public void Initialize() {
var parameter = /*...test data that i need in all tests...*/
this.controller = new Controller(parameter)
}
[TestMethod]
public void test1 {
result = controller.FirstMethod();
//assert something
}
[TestMethod]
public void test2 {
result = controller.SecondMethod();
//assert something
}
/*..
创建一个方法以 运行 初始化并设置需要可用于该方法中所有测试的任何对象。 (该方法将在每次测试之前重新运行,因此不要指望状态会持续存在。)
[TestInitialize]
public void Initialize()
{
// your common setup code here
this.controller = ...
}
(TestInitialize
是 MS 测试下的属性,类似的属性在您可能使用的大多数其他测试框架下都可用。)
我通常对将在测试中使用的存根和模拟执行此操作。至于设置 class 我实际上正在测试,我通常会在测试方法本身中处理它或将其重构为私有辅助方法,但这只是个人偏好。如果被测class的设置对于你所有的测试也是统一的,那么它也可以进入初始化方法。
你混合了几种东西所以让我指出这种方法的一些错误。
隔离
一个好的单元测试是一种在速度、重复性等其他几个方面中是孤立的测试。这意味着其他测试的结果或顺序不应影响另一个测试的结果。良好的单元测试的每个方面都同样重要,因为如果没有它们,您可能一开始就不会使用单元测试。
设置
如果您的测试依赖于特定的代码片段才能正常工作,那么您可以在适当的范围内对其进行初始化(汇编或 class 初始化)。您为此使用 [Initalize]
或 [AssemblyInitialize]
注释(大多数时候您需要 class 初始化)。
重要提示:这些是不是测试!
测试代码,不是测试
再看看上面显示的代码。让我总结一下你的工作:
- 创建模拟
- 创建
Film
对象
- 将存储库设置为 return 电影
- 创建注入模拟的控制器
- 断言控制器已创建
- 断言控制器属于某种类型
- 设置实例级变量
这是错误的,原因有 3 个:
- 您为 return 数据设置了一个模拟,但从未对其进行测试。
- 您创建一个控制器,然后测试它是否已创建以及它是否属于正确的实例:尽可能毫无意义的操作。
- 您分配的实例级变量不会对其他测试产生任何影响(也不应该:请参阅良好单元测试的原则)。
您的代码中没有任何地方在测试您的实际问题域,您只是在设置用于测试的东西。另请注意,为您的模拟使用一些更清晰的名称不会有什么坏处。也不能保证单个 class 中单元测试的顺序是 运行.
我认为你必须使用装饰器 [TestInitialize]
这用于在执行所有 [TestMethods] 之前初始化测试序列
我也需要在其他测试中的第一个测试中初始化的对象。 为了防止代码重复,我想将我在第一个测试中创建的对象保存在一个全局变量中。这就是我所做的:
namespace Project.WebUIV2.Tests {
[TestClass]
public class FilmSelectieControllerTests {
private FilmSelectieController controller;
[TestMethod]
public void CanInitializeController() {
Mock<IRepository<Voorstelling>> mockIRepository1 = new Mock<IRepository<Voorstelling>>();
Mock<IRepository<Film>> mockIRepository2 = new Mock<IRepository<Film>>();
Mock<IRepository<Zaal>> mockIRepository3 = new Mock<IRepository<Zaal>>();
Film film = new Film { titel = "Film" };
mockIRepository2.Setup(m => m.Add(film));
var repository1 = mockIRepository1.Object;
var repository2 = mockIRepository2.Object;
var repository3 = mockIRepository3.Object;
var controller = new FilmSelectieController(repository1, repository2, repository3);
Assert.IsNotNull(controller);
Assert.IsInstanceOfType(controller, typeof(FilmSelectieController));
this.controller = controller;
}
[TestMethod]
public void IsCreated() {
Assert.IsInstanceOfType(controller, typeof(FilmSelectieController));
}
}
}
测试方法 CanInitializeController() 成功,而 isCreated() 失败。
在第一个测试中,我创建了 FilmSelectieController 对象。
如何在接下来的测试中使用该对象?
感谢 Anthony Pegram
解法:
..*/
private Controller controller;
[TestInitialize]
public void Initialize() {
var parameter = /*...test data that i need in all tests...*/
this.controller = new Controller(parameter)
}
[TestMethod]
public void test1 {
result = controller.FirstMethod();
//assert something
}
[TestMethod]
public void test2 {
result = controller.SecondMethod();
//assert something
}
/*..
创建一个方法以 运行 初始化并设置需要可用于该方法中所有测试的任何对象。 (该方法将在每次测试之前重新运行,因此不要指望状态会持续存在。)
[TestInitialize]
public void Initialize()
{
// your common setup code here
this.controller = ...
}
(TestInitialize
是 MS 测试下的属性,类似的属性在您可能使用的大多数其他测试框架下都可用。)
我通常对将在测试中使用的存根和模拟执行此操作。至于设置 class 我实际上正在测试,我通常会在测试方法本身中处理它或将其重构为私有辅助方法,但这只是个人偏好。如果被测class的设置对于你所有的测试也是统一的,那么它也可以进入初始化方法。
你混合了几种东西所以让我指出这种方法的一些错误。
隔离
一个好的单元测试是一种在速度、重复性等其他几个方面中是孤立的测试。这意味着其他测试的结果或顺序不应影响另一个测试的结果。良好的单元测试的每个方面都同样重要,因为如果没有它们,您可能一开始就不会使用单元测试。
设置
如果您的测试依赖于特定的代码片段才能正常工作,那么您可以在适当的范围内对其进行初始化(汇编或 class 初始化)。您为此使用 [Initalize]
或 [AssemblyInitialize]
注释(大多数时候您需要 class 初始化)。
重要提示:这些是不是测试!
测试代码,不是测试
再看看上面显示的代码。让我总结一下你的工作:
- 创建模拟
- 创建
Film
对象 - 将存储库设置为 return 电影
- 创建注入模拟的控制器
- 断言控制器已创建
- 断言控制器属于某种类型
- 设置实例级变量
这是错误的,原因有 3 个:
- 您为 return 数据设置了一个模拟,但从未对其进行测试。
- 您创建一个控制器,然后测试它是否已创建以及它是否属于正确的实例:尽可能毫无意义的操作。
- 您分配的实例级变量不会对其他测试产生任何影响(也不应该:请参阅良好单元测试的原则)。
您的代码中没有任何地方在测试您的实际问题域,您只是在设置用于测试的东西。另请注意,为您的模拟使用一些更清晰的名称不会有什么坏处。也不能保证单个 class 中单元测试的顺序是 运行.
我认为你必须使用装饰器 [TestInitialize]
这用于在执行所有 [TestMethods] 之前初始化测试序列