我如何编写失败测试以在没有外部状态的 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 方法,这当然会失败。