C# 在理解如何在单元测试中使用Mock时遇到困难
我定义了以下单元测试:C# 在理解如何在单元测试中使用Mock时遇到困难,c#,java,unit-testing,mocking,C#,Java,Unit Testing,Mocking,我定义了以下单元测试: [TestMethod] //@Test for the Java crowd public void In_The_Beginning_All_The_Board_Is_Black() { IBoard board = new Board(new Size(10, 22)); BoardEngine boardEngine = new BoardEngine(board); for (int y = 0; y < boardEngine.
[TestMethod] //@Test for the Java crowd
public void In_The_Beginning_All_The_Board_Is_Black()
{
IBoard board = new Board(new Size(10, 22));
BoardEngine boardEngine = new BoardEngine(board);
for (int y = 0; y < boardEngine.Size.Width; ++y)
{
for (int x = 0; x < boardEngine.Size.Width; ++x)
{
Assert.AreEqual<Color>(Color.Black, boardEngine.GetCellAt(new Point(x, y)).Color);
}
}
}
而IBoard
的定义如下:
public interface IBoard
{
Size Size { get; }
BoardCell GetCellAt(Point location);
void SetCellAt(Point location, BoardCell cell);
void SetAllCellsTo(Color color);
}
我在这里采取了正确的方法吗?也许问题在于,由于BoardEngine
基本上是将其所有工作委托给IBoard
,我应该测试IBoard
实现,而不是BoardEngine
编辑 所以,如果我正确理解你们想告诉我的话,我有两个选择:
谢谢这取决于您使用的模拟框架。使用Rhino.Mocks时,它会如下所示:
var board = MockRepository.GenerateStub<IBoard>();
board.Size = new Size(2,2);
BoardEngine boardEngine = new BoardEngine(board);
board.AssertWasCalled(b => b.SetAllCellsTo(Color.Black),
options => options.Repeat.Times(1));
var board=MockRepository.GenerateStub();
板尺寸=新尺寸(2,2);
BoardEngine BoardEngine=新的BoardEngine(板);
调用board.assertwas(b=>b.SetAllCellsTo(Color.Black),
options=>options.Repeat.Times(1));
在这里,您创建模拟或存根,执行您正在测试的操作,然后断言预期的事情发生了。在本例中,您希望调用一次SetAllCellsTo(Color.Black)
您不关心是否所有的单元格现在都是黑色的,因为这是单元之外的行为——甚至是被测类之外的行为,在本例中是BoardEngine
。您要测试的是BoardEngine
在注入依赖项实例化时调用该依赖项上的指定方法
编辑以响应OP edit
您在编辑中列出的两个选项是正确的,但不是相互排斥的。我建议您进行单元测试,以确保每项功能在各种进入条件下都能按预期工作,并进行测试以确保交互在更高级别上工作
请记住,您可以通过(1)测试对board.SetAllCellsTo(Color.Black)
的调用是否实际工作,独立于BoardEngine
,然后(2)测试BoardEngine
调用[tested to be working]方法。尽管如此,您还是应该进行更高级别的测试,以确保所有内容都按照预期进行,并且没有副作用
从什么测试开始有点主观。在使用TDD实现功能方面,您需要对系统的工作方式有一个很好的了解--
BoardEngine
和Board
将如何协同工作。您可以定义这两个接口并概述一个测试,但在实现这两个接口之前,您无法实际执行测试,如果编写测试,您将无法编译它,因为您将没有可实例化的类。另一方面,您可以在实现每个接口时编写单元测试。从IBoard
开始,因为它具有较少的依赖项。开始执行Board:IBoard,并在执行过程中覆盖它。当您知道对SetAllColorsTo()
的调用按预期工作时,您将更熟悉调用该方法的BoardEngine
构造函数的单元测试。这将根据您使用的模拟框架而有所不同。使用Rhino.Mocks时,它会如下所示:
var board = MockRepository.GenerateStub<IBoard>();
board.Size = new Size(2,2);
BoardEngine boardEngine = new BoardEngine(board);
board.AssertWasCalled(b => b.SetAllCellsTo(Color.Black),
options => options.Repeat.Times(1));
var board=MockRepository.GenerateStub();
板尺寸=新尺寸(2,2);
BoardEngine BoardEngine=新的BoardEngine(板);
调用board.assertwas(b=>b.SetAllCellsTo(Color.Black),
options=>options.Repeat.Times(1));
在这里,您创建模拟或存根,执行您正在测试的操作,然后断言预期的事情发生了。在本例中,您希望调用一次SetAllCellsTo(Color.Black)
您不关心是否所有的单元格现在都是黑色的,因为这是单元之外的行为——甚至是被测类之外的行为,在本例中是BoardEngine
。您要测试的是BoardEngine
在注入依赖项实例化时调用该依赖项上的指定方法
编辑以响应OP edit
您在编辑中列出的两个选项是正确的,但不是相互排斥的。我建议您进行单元测试,以确保每项功能在各种进入条件下都能按预期工作,并进行测试以确保交互在更高级别上工作
请记住,您可以通过(1)测试对board.SetAllCellsTo(Color.Black)
的调用是否实际工作,独立于BoardEngine
,然后(2)测试BoardEngine
调用[tested to be working]方法。尽管如此,您还是应该进行更高级别的测试,以确保所有内容都按照预期进行,并且没有副作用
从什么测试开始有点主观。在使用TDD实现功能方面,您需要对系统的工作方式有一个很好的了解--BoardEngine
和Board
将如何协同工作。您可以定义这两个接口并概述一个测试,但在实现这两个接口之前,您无法实际执行测试,如果编写测试,您将无法编译它,因为您将没有可实例化的类。另一方面,您可以在实现每个接口时编写单元测试。Sta
public class BoardEngineTest {
@Test
public void engineShouldSetCellsBlack() {
// 1. create mock
IBoard mockBoard = EasyMock.createMock(IBoard.class);
// 2. program mock
EasyMock.reset(mockBoard); // put in record mode
// this doesn't actually happen now, the mock is just
// being programmed to expect this method call with this
// argument
mockBoard.setAllCellsTo(Color.Black);
// 3. put in replay mode - it's alive at this point!
EasyMock.replay(mockBoard);
// do something that cause the mock to be used
BoardEngine engine = new BoardEngine(mockBoard);
// 4. make sure cells were actually set to black!
EasyMock.verify(mockBoard);
}
}