用于验证基本 class 方法被调用的单元测试
Unit test to verify that a base class method is called
我有一个基地class:
public abstract class MyBaseClass
{
protected virtual void Method1()
{
}
}
和派生的 class:
public class MyDerivedClass : MyBaseClass
{
public void Method2()
{
base.Method1();
}
}
我想为 Method2
编写一个单元测试,以验证它在基础 class 上调用 Method1
。我正在使用 Moq 作为我的模拟库。这可能吗?
我遇到了一个相关的 SO link:
Mocking a base class method call with Moq
其中第二个答案表明可以通过在模拟对象上将 CallBase
属性 设置为 true 来实现。但是,尚不清楚这将如何验证对基本 class 方法(上例中的 Method1
)的调用。
感谢任何帮助。
从派生 class 的角度模拟基 class 是不可能的。在您的简单示例中,我会建议两个选项之一。
选项 1:如果 MyDerivedClass
真的不应该关心 MyBaseClass
在做什么,那么使用依赖注入!耶抽象!
public class MyClass
{
private readonly IUsedToBeBaseClass myDependency;
public MyClass(IUsedToBeBaseClass myDependency){
_myDependency = myDependency;
}
public void Method2()
{
_myDependency.Method1();
}
}
在试验区的其他地方...
[TestClass]
public class TestMyDependency {
[TestMethod]
public void TestThatMyDependencyIsCalled() {
var dependency = new Mock<IUsedToBeBaseClass>();
var unitUnderTest = new MyClass(dependency.Object);
var unitUnderTest.Method2();
dependency.Verify(x => x.Method1(), Times.Once);
}
}
选项 2:如果 MyDerivedClass
需要知道 MyBaseClass
在做什么,那么 测试 MyBaseClass
是否在做正确的事情.
在替代试验地...
[TestClass]
public class TestMyDependency {
[TestMethod]
public void TestThatMyDependencyIsCalled() {
var unitUnderTest = new MyDerivedClass();
var unitUnderTest.Method2();
/* verify base class behavior #1 inside Method1() */
/* verify base class behavior #2 inside Method1() */
/* ... */
}
}
单元测试应该验证行为,而不是实现。这有几个原因:
- 结果才是目标,而不是你如何得到结果
- 测试结果允许您改进实现而无需重新编写测试
- 实现更难模拟
您可能能够放入钩子或创建模拟来验证基本方法是否被调用,但您真的关心如何 答案达成了,还是你在乎答案是对?
如果您需要的特定实现具有可以验证的副作用,那么那 就是您应该验证的。
您所描述的不是对代码的测试,而是对语言行为的测试。这很好,因为这是确保语言按照我们认为的方式运行的好方法。我在学习的时候曾经写过很多小的控制台应用程序。我希望那时我就知道单元测试,因为这是一种更好的方法。
但是一旦您测试并确认 语言 的行为符合您的预期,我就不会继续为此编写测试。您可以只测试代码的行为。
这是一个真正简单的例子:
public class TheBaseClass
{
public readonly List<string> Output = new List<string>();
public virtual void WriteToOutput()
{
Output.Add("TheBaseClass");
}
}
public class TheDerivedClass : TheBaseClass
{
public override void WriteToOutput()
{
Output.Add("TheDerivedClass");
base.WriteToOutput();
}
}
单元测试
[TestMethod]
public void EnsureDerivedClassCallsBaseClass()
{
var testSubject = new TheDerivedClass();
testSubject.WriteToOutput();
Assert.IsTrue(testSubject.Output.Contains("TheBaseClass"));
}
我有一个基地class:
public abstract class MyBaseClass
{
protected virtual void Method1()
{
}
}
和派生的 class:
public class MyDerivedClass : MyBaseClass
{
public void Method2()
{
base.Method1();
}
}
我想为 Method2
编写一个单元测试,以验证它在基础 class 上调用 Method1
。我正在使用 Moq 作为我的模拟库。这可能吗?
我遇到了一个相关的 SO link:
Mocking a base class method call with Moq
其中第二个答案表明可以通过在模拟对象上将 CallBase
属性 设置为 true 来实现。但是,尚不清楚这将如何验证对基本 class 方法(上例中的 Method1
)的调用。
感谢任何帮助。
从派生 class 的角度模拟基 class 是不可能的。在您的简单示例中,我会建议两个选项之一。
选项 1:如果 MyDerivedClass
真的不应该关心 MyBaseClass
在做什么,那么使用依赖注入!耶抽象!
public class MyClass
{
private readonly IUsedToBeBaseClass myDependency;
public MyClass(IUsedToBeBaseClass myDependency){
_myDependency = myDependency;
}
public void Method2()
{
_myDependency.Method1();
}
}
在试验区的其他地方...
[TestClass]
public class TestMyDependency {
[TestMethod]
public void TestThatMyDependencyIsCalled() {
var dependency = new Mock<IUsedToBeBaseClass>();
var unitUnderTest = new MyClass(dependency.Object);
var unitUnderTest.Method2();
dependency.Verify(x => x.Method1(), Times.Once);
}
}
选项 2:如果 MyDerivedClass
需要知道 MyBaseClass
在做什么,那么 测试 MyBaseClass
是否在做正确的事情.
在替代试验地...
[TestClass]
public class TestMyDependency {
[TestMethod]
public void TestThatMyDependencyIsCalled() {
var unitUnderTest = new MyDerivedClass();
var unitUnderTest.Method2();
/* verify base class behavior #1 inside Method1() */
/* verify base class behavior #2 inside Method1() */
/* ... */
}
}
单元测试应该验证行为,而不是实现。这有几个原因:
- 结果才是目标,而不是你如何得到结果
- 测试结果允许您改进实现而无需重新编写测试
- 实现更难模拟
您可能能够放入钩子或创建模拟来验证基本方法是否被调用,但您真的关心如何 答案达成了,还是你在乎答案是对?
如果您需要的特定实现具有可以验证的副作用,那么那 就是您应该验证的。
您所描述的不是对代码的测试,而是对语言行为的测试。这很好,因为这是确保语言按照我们认为的方式运行的好方法。我在学习的时候曾经写过很多小的控制台应用程序。我希望那时我就知道单元测试,因为这是一种更好的方法。
但是一旦您测试并确认 语言 的行为符合您的预期,我就不会继续为此编写测试。您可以只测试代码的行为。
这是一个真正简单的例子:
public class TheBaseClass
{
public readonly List<string> Output = new List<string>();
public virtual void WriteToOutput()
{
Output.Add("TheBaseClass");
}
}
public class TheDerivedClass : TheBaseClass
{
public override void WriteToOutput()
{
Output.Add("TheDerivedClass");
base.WriteToOutput();
}
}
单元测试
[TestMethod]
public void EnsureDerivedClassCallsBaseClass()
{
var testSubject = new TheDerivedClass();
testSubject.WriteToOutput();
Assert.IsTrue(testSubject.Output.Contains("TheBaseClass"));
}