我如何编写失败测试以在没有外部状态的 if 语句中添加另一个分支
How do i write a failing test to add another branch in an if statement without external state
使用此代码:
Public class Processor {
Public Processor(Ifoo colloborator, Ibar otherCollobotator)
Public void Process() {
// if (newFoo)
// new action
If (foo)
this.colloborator.doSomething();
If (bar)
this.colloborator.doSomethingElse();
Else this.otherColloborator.doSomethingCompletelyDiffetent();
}
我想在顶部添加另一个分支来做其他事情(已注释掉)。我知道一种方法,它涉及使用适当的 mock/spy.
验证或不验证对协作者的调用
需要明确的是,我已经成功地完成了这项工作,并且使用 TDD 'without' 引入了另一个合作者。
你会如何解决这个问题?从测试第一的角度来看?
我认为最终它可以用称为可插拔的东西重构 object/adapter。
就像你说的,你需要检查当条件为真时调用new action
,当条件为假时调用new action is not called
。所以,首先我们要定义我们的新接口:
public interface INewAction
{
void NewAction();
}
然后,我们修改我们的处理器(注意我们还没有添加新的 if 分支):
public class Processor {
private readonly INewAction _newAction;
public Processor(Ifoo colloborator, Ibar otherCollobotator, INewAction newAction)
{
// whatever we had before
_newAction = newAction;
}
public void Process() {
if (foo)
this.colloborator.doSomething();
of (bar)
this.colloborator.doSomethingElse();
else this.otherColloborator.doSomethingCompletelyDiffetent();
}
现在我们编写测试用例:
[TestClass]
public class ProcessorTests
{
[TestMethod]
public void Process_GivenNewFoo_CallsNewAction()
{
// arrange 'newfoo' condition
// mockout our processor, e.g.
var mockNewAction = new Mock<INewAction>(); // this is Moq, for others use appropriate syntax, e.g. Substitute.For<INewAction>() for NSubstitute etc.
mockNewAction.Setup(x => x.NewAction()).Verifiable();
var target = new Processor(null, null, mockNewAction.Object);
target.Process();
mockNewAction.Verify(x => x.NewAction(), Times.Once);
}
[TestMethod]
public void Process_GivenNewFoo_False_DoesNotCallNewAction()
{
// arrange 'newfoo' condition to be false
// mockout our processor, e.g.
var mockNewAction = new Mock<INewAction>(); // this is Moq, for others use appropriate syntax, e.g. Substitute.For<INewAction>() for NSubstitute etc.
mockNewAction.Setup(x => x.NewAction()).Verifiable();
var target = new Processor(null, null, mockNewAction.Object);
target.Process();
mockNewAction.Verify(x => x.NewAction(), Times.Never);
}
}
当我们 运行 他们时,第二个测试将通过 -> 好吧,这是意料之中的,因为本质上行为是 if NOT newfoo then don't call it
。但是第一个测试会失败(TDD 方法也是如此)。
现在我们再次修改处理器,只是 Process()
方法:
public void Process() {
if(newFoo)
{
_newAction.NewAction();
}
if (foo)
this.colloborator.doSomething();
of (bar)
this.colloborator.doSomethingElse();
else this.otherColloborator.doSomethingCompletelyDiffetent();
}
至此,两个测试都通过了,我们完成了 TDD 周期。
假设你的新动作也调用了协作者,你可以模拟它。
RhinoMocks 示例:
[TestMethod]
public void Test()
{
//Arrange
ICollaborator mock = MockRepository.GenerateMock<ICollaborator>();
Processor myProc = new Processor(mock, ...);
//Act
myProc.Process();
//Assert
mock.AssertWasCalled(x => x.MethodToBeCalled);
}
如果您不更改 Process 方法,这当然会失败。
使用此代码:
Public class Processor {
Public Processor(Ifoo colloborator, Ibar otherCollobotator)
Public void Process() {
// if (newFoo)
// new action
If (foo)
this.colloborator.doSomething();
If (bar)
this.colloborator.doSomethingElse();
Else this.otherColloborator.doSomethingCompletelyDiffetent();
}
我想在顶部添加另一个分支来做其他事情(已注释掉)。我知道一种方法,它涉及使用适当的 mock/spy.
验证或不验证对协作者的调用
需要明确的是,我已经成功地完成了这项工作,并且使用 TDD 'without' 引入了另一个合作者。
你会如何解决这个问题?从测试第一的角度来看?
我认为最终它可以用称为可插拔的东西重构 object/adapter。
就像你说的,你需要检查当条件为真时调用new action
,当条件为假时调用new action is not called
。所以,首先我们要定义我们的新接口:
public interface INewAction
{
void NewAction();
}
然后,我们修改我们的处理器(注意我们还没有添加新的 if 分支):
public class Processor {
private readonly INewAction _newAction;
public Processor(Ifoo colloborator, Ibar otherCollobotator, INewAction newAction)
{
// whatever we had before
_newAction = newAction;
}
public void Process() {
if (foo)
this.colloborator.doSomething();
of (bar)
this.colloborator.doSomethingElse();
else this.otherColloborator.doSomethingCompletelyDiffetent();
}
现在我们编写测试用例:
[TestClass]
public class ProcessorTests
{
[TestMethod]
public void Process_GivenNewFoo_CallsNewAction()
{
// arrange 'newfoo' condition
// mockout our processor, e.g.
var mockNewAction = new Mock<INewAction>(); // this is Moq, for others use appropriate syntax, e.g. Substitute.For<INewAction>() for NSubstitute etc.
mockNewAction.Setup(x => x.NewAction()).Verifiable();
var target = new Processor(null, null, mockNewAction.Object);
target.Process();
mockNewAction.Verify(x => x.NewAction(), Times.Once);
}
[TestMethod]
public void Process_GivenNewFoo_False_DoesNotCallNewAction()
{
// arrange 'newfoo' condition to be false
// mockout our processor, e.g.
var mockNewAction = new Mock<INewAction>(); // this is Moq, for others use appropriate syntax, e.g. Substitute.For<INewAction>() for NSubstitute etc.
mockNewAction.Setup(x => x.NewAction()).Verifiable();
var target = new Processor(null, null, mockNewAction.Object);
target.Process();
mockNewAction.Verify(x => x.NewAction(), Times.Never);
}
}
当我们 运行 他们时,第二个测试将通过 -> 好吧,这是意料之中的,因为本质上行为是 if NOT newfoo then don't call it
。但是第一个测试会失败(TDD 方法也是如此)。
现在我们再次修改处理器,只是 Process()
方法:
public void Process() {
if(newFoo)
{
_newAction.NewAction();
}
if (foo)
this.colloborator.doSomething();
of (bar)
this.colloborator.doSomethingElse();
else this.otherColloborator.doSomethingCompletelyDiffetent();
}
至此,两个测试都通过了,我们完成了 TDD 周期。
假设你的新动作也调用了协作者,你可以模拟它。
RhinoMocks 示例:
[TestMethod]
public void Test()
{
//Arrange
ICollaborator mock = MockRepository.GenerateMock<ICollaborator>();
Processor myProc = new Processor(mock, ...);
//Act
myProc.Process();
//Assert
mock.AssertWasCalled(x => x.MethodToBeCalled);
}
如果您不更改 Process 方法,这当然会失败。