我有一个名为TestMakeAValidCall()
的单元测试。它测试我的手机应用程序拨打有效电话。
我即将编写另一个名为TestShowCallMessage()
的测试,需要为测试进行有效调用。在该测试中调用TestMakeAValidCall()
是不好的形式?
作为参考,这是我的TestMakeAValidCall()
测试。
[TestMethod]
public void TestMakeAValidCall()
{
//Arrange
phone.InCall = false;
phone.CurrentNumber = "";
// Stub the call to the database
data.Expect(x => x.GetWhiteListData()).
Return(FillTestObjects.GetSingleEntryWhiteList());
// Get some bogus data
string phoneNumber = FillTestObjects.GetSingleEntryWhiteList().
First().PhoneNumber;
// Stub th call to MakeCall() so that it looks as if a call was made.
phone.Expect(x => x.MakeCall(phoneNumber)).
WhenCalled(invocation =>
{
phone.CurrentNumber = phoneNumber;
phone.InCall = true;
});
//Act
// Select the phone number
deviceControlForm.SelectedNumber = phoneNumber;
// Press the call button to make a call.
deviceMediator.CallButtonPressed();
//Assert
Assert.IsTrue(phone.InCall);
Assert.IsTrue(phone.CurrentNumber == phoneNumber);
}
答案 0 :(得分:52)
将设置重构为另一个方法,并从两个测试中调用该方法。测试不应该调用其他测试。
答案 1 :(得分:11)
恕我直言,您应该执行以下操作之一:
答案 2 :(得分:6)
我认为这是一个坏主意。您希望您的单元测试仅测试一件事和一件事。不是通过其他测试创建调用,而是模拟调用并将其作为参数传递。
答案 3 :(得分:6)
提供一个反点:
我坚信精心设计的单元测试应该相互依赖!
当然,只有当测试框架知道这些依赖关系时才有意义,以便在依赖关系失败时它可以停止运行依赖测试。更好的是,这样的框架可以将夹具从测试传递到测试,这样可以构建在不断增长和扩展的夹具上,而不是为每次单个测试从头开始重建。当然,当多个测试取决于同一个例子时,进行缓存以保证不会引入副作用。
我们在JExample extension for JUnit中实施了这个想法。虽然有Ruby和Smalltalk以及most recent release of PHPUnit picked up both our ideas: dependencies and fixture reuse的端口,但还没有C#端口。
答案 4 :(得分:4)
单元测试应根据定义测试代码的一个单元/功能。让它调用其他单元测试使它测试多个单元。我把它分解成个别测试。
答案 5 :(得分:2)
是的 - 单元测试应该是分开的,并且应该仅针对一件事(或至少少量紧密相关的事情)进行测试。顺便说一下,在你的测试方法中调用data.Expect和phone.Expect正在创建期望而不是存根调用,如果你重构,这会使你的测试变得脆弱......
答案 6 :(得分:1)
单元与模块......我们还认为测试也应该依赖于可重用的方法,并且应该在api级别测试测试类的集成。许多人只测试单个类,但很多错误都是在类级别之间进行集成。我们还使用verifydesign来保证api不依赖于实现。这允许您在不接触测试的情况下重构整个组件/模块(我们实际上经历了一次并且它工作得很好)。当然,任何体系结构更改都会强制您重构测试,但至少模块中的设计更改不会导致测试重构工作(除非您更改api的行为当然隐含地像触发更多事件而不是以前那样“无论如何都会“改变api”。
答案 7 :(得分:0)
“有人能对这种情况下的重构情况有所了解吗?– PhilipBergström,2015年11月28日,15:33”
我目前正在做这样的事情,这就是我想出的:
请注意,ProcessorType和BuildProcessor都调用TestLevels
除该事实外,实际内容不重要
使用XUnit和Shouldly NuGet软件包
private static void TestLevels(ArgProcessor incomingProcessor)
{
Action<ProcessorLevel, int> currentLevelIteration = null;
currentLevelIteration = (currentProcessor, currentLevel) =>
{
currentProcessor.CurrentLevel.ShouldBeEquivalentTo(currentLevel);
ProcessorLevel nextProcessor = currentProcessor.CurrentProcessor;
if (nextProcessor != null)
currentLevelIteration(nextProcessor, currentLevel + 1);
};
currentLevelIteration(incomingProcessor, 0);
}
[Theory]
[InlineData(typeof(Build), "Build")]
public void ProcessorType(Type ProcessorType, params string[] args)
{
ArgProcessor newCLI = new OriWeb_CLI.ArgProcessor(args);
IncomingArgumentsTests.TestLevels(newCLI);
newCLI.CurrentProcessor.ShouldBeOfType(ProcessorType);
}
[Theory]
[InlineData(typeof(Build.TypeScript), "TypeScript")]
[InlineData(typeof(Build.CSharp), "CSharp")]
public void BuildProcessors(Type ProcessorType, params string[] args)
{
List<string> newArgs = new List<string> {"Build"};
foreach(string arg in args) newArgs.Add(arg);
ArgProcessor newCLI = new OriWeb_CLI.ArgProcessor(newArgs.ToArray());
IncomingArgumentsTests.TestLevels(newCLI);
newCLI.CurrentProcessor.CurrentProcessor.ShouldBeOfType(ProcessorType);
}