Unit testing TDD:向测试状态添加方法

Unit testing TDD:向测试状态添加方法,unit-testing,tdd,Unit Testing,Tdd,所以,我开始为一个简单的程序编写一些逻辑(附带玩具游戏)。您有一个特定的ship(称为设置),它是ship+模块。您从一个基于船的空设置开始,然后向该设置添加模块。船上还有一个编号的模块位置阵列 var setup = new Setup(ship); // ship is a stub (IShip) defined someplace else var module = new Mock<IModule>().Object; setup.AddModule(module, 1);

所以,我开始为一个简单的程序编写一些逻辑(附带玩具游戏)。您有一个特定的ship(称为设置),它是ship+模块。您从一个基于船的空设置开始,然后向该设置添加模块。船上还有一个编号的模块位置阵列

var setup = new Setup(ship); // ship is a stub (IShip) defined someplace else
var module = new Mock<IModule>().Object;
setup.AddModule(module, 1); // 1 = which position
这听起来可能真的很愚蠢,我什么都不担心,但出于某种愚蠢的原因,我只关心添加一个方法来断言测试通过了

这很好,实际上是TDD推出的设计过程的一部分吗?例如,我知道我需要一个AddModule方法,因为我想测试它,而这需要一个GetModule方法来测试,这只是我通过TDD设计的一个演变

或者这是一种气味,因为我甚至不知道我的代码中是否真的需要GetModule,它只会在测试中使用


例如,添加一个模块将最终影响设置的不同状态(装甲、盾牌、火力等)。问题是这些将是复杂的,我想从一个简单的测试开始。但最后,这些是我关心的公共属性——设置是由其统计数据定义的,而不是由模块列表定义的。

有趣的问题。我很高兴听到你先写测试

如果您让设计通过测试表现出来,那么您更有可能只构建您需要的部分。但这是最好的设计吗?也许不会,但不要因此而气馁——您的add方法很有效


现在判断您以后是否需要GetModule方法可能还为时过早。现在,构建您需要的功能,并变为绿色,然后慢慢地重构它(再次从红色变为绿色),以获得您想要的设计。

有趣的问题。我很高兴听到你先写测试

如果您让设计通过测试表现出来,那么您更有可能只构建您需要的部分。但这是最好的设计吗?也许不会,但不要因此而气馁——您的add方法很有效


现在判断您以后是否需要GetModule方法可能还为时过早。现在,构建您需要的功能,并变为绿色,然后慢慢地重构它(再次从红色变为绿色),以获得您想要的设计。

我会小心在我的类中引入一个只用于测试的公共方法

您可以通过多种方式来测试这一点:

反射:GetModule方法是类中的私有方法(如果“stats”是私有的,这也可以工作),您可以通过反射在测试方法中访问它。这将很好地工作,唯一的问题是如果您更改私有方法的名称或添加/删除一些变量,您将不会得到任何编译器错误(但是,当然,您的测试将失败,并且您将提前知道)

继承:GetModule方法可以被保护(只有继承可见),并且您的测试类可以从主类继承。通过这种方式,您的测试类可以访问此方法,但它并没有真正暴露于外部世界


断言副作用:这是您真正思考在系统中添加模块意味着什么的地方。如果它会像你所说的那样影响一些“统计数据”,你可以编写一些测试来断言这些统计数据是经过适当修改的。

我会小心在我的类中引入一个只用于测试的公共方法

您可以通过多种方式来测试这一点:

反射:GetModule方法是类中的私有方法(如果“stats”是私有的,这也可以工作),您可以通过反射在测试方法中访问它。这将很好地工作,唯一的问题是如果您更改私有方法的名称或添加/删除一些变量,您将不会得到任何编译器错误(但是,当然,您的测试将失败,并且您将提前知道)

继承:GetModule方法可以被保护(只有继承可见),并且您的测试类可以从主类继承。通过这种方式,您的测试类可以访问此方法,但它并没有真正暴露于外部世界


断言副作用:这是您真正思考在系统中添加模块意味着什么的地方。如果它会像你所说的那样影响某些“统计数据”,你可以编写测试,断言统计数据已经被适当修改。

设计的一部分是从简单方法的小步骤开始,然后在足够支持它的情况下发展成复杂的统计数据(最终放弃此方法并更改测试)。在进行TDD时,不要期望您编写的第一个测试是针对理想接口的。随着设计的发展,一些杂乱的东西会逐渐消失,这是可以接受的


也就是说,如果您认为该方法没有公共用途,请尽量限制其可见性,使其对测试代码合理。尽管当你开始构建系统的其余部分时,这一点最终也会消失,并且作为set方法的一个副作用,有一些真实的东西需要测试。

设计的一部分是从一个简单的方法开始,然后发展成复杂的统计数据(最终放弃此方法并改变测试)当足够的人支持它的时候。在进行TDD时,不要期望您编写的第一个测试是针对理想接口的。随着设计的发展,一些杂乱的东西会逐渐消失,这是可以接受的


也就是说,如果您认为该方法没有公共用途,请尽量限制其可见性,使其对测试代码合理。尽管在构建系统的其余部分时,这一点最终也会消失,并且作为set方法的一个副作用,有一些真实的东西需要测试。

或者您可以添加InternalsVisibleTo属性,让您的测试看到内部方法。或者您可以添加InternalsVisibleTo属性,让您的测试看到内部方法。
Assert.AreEqual(module, setup.GetModule(1));