单元测试有哪些流行的命名约定?[关闭]


203

一般

  • 所有测试均遵循相同的标准。
  • 明确每个测试状态是什么。
  • 明确预期的行为。

例子

1)MethodName_StateUnderTest_ExpectedBehavior

Public void Sum_NegativeNumberAs1stParam_ExceptionThrown() 

Public void Sum_NegativeNumberAs2ndParam_ExceptionThrown () 

Public void Sum_simpleValues_Calculated ()

资料来源:单元测试的命名标准

2)用下划线分隔每个单词

Public void Sum_Negative_Number_As_1st_Param_Exception_Thrown() 

Public void Sum_Negative_Number_As_2nd_Param_Exception_Thrown () 

Public void Sum_Simple_Values_Calculated ()

其他

  • Test结束方法名称
  • 以类名开头的方法名

请参阅行为驱动开发

Answers:


94

在这个男人身上,我几乎和你在一起。您使用的命名约定是:

  • 清除每个测试状态是什么。
  • 具体说明预期的行为。

您还需要测试名称中的什么?

Ray的答案相反,我认为Test前缀不是必需的。这是测试代码,我们知道。如果您需要这样做来标识代码,那么您会遇到更大的问题,因此不应将测试代码与生产代码混淆。

至于下划线的长度和用途,其测试代码,到底谁在乎?只要您和您的团队都能看到它,只要它可读且清楚测试的内容,那就继续!:)

话虽如此,我仍然对使用冒险进行测试和博客还很陌生 :)


20
“只要是可读且清晰的”和“谁在乎”的轻微矛盾。好吧,每个人都在乎它的可读性和清晰性,所以这才是重要的。:-)
David Victor

1
前缀的另一个参数。在IDE中搜索文件时,您可以通过以Test和您的类名开头轻松地搜索测试用例。如果类名和测试类名相同,我们将总是不得不暂停并读取两个文件的路径
该用户需要帮助

@THISUSERNEEDSHELP我认为,拥有一个良好的文件夹结构(例如src / libssrc / tests)可以轻松克服您的观点。我知道某些测试运行器框架确实需要像test这样的前缀来标识测试代码,因此在这种情况下将无法避免,但是对于其他情况,它可以是重复的不需要前缀。
negrotico19

@ negrotico19当您Search Everywhere(换档)或Find a Class By Name(CMD O)时,我正在考虑类似IntelliJ的情况。我得到它通过任一文件夹结构或模块结构有所区别,但是当我们寻找的东西,我们已经知道我们要搜索的内容。例如,如果我正在寻找测试,我想将搜索范围限制为test然后搜索名称,而不是搜索名称,然后用眼睛手动过滤掉测试。这是一个很小的区别,但是“测试[类名]”要容易得多,并且只弹出一个窗口即可减少精神负担
该用户需要帮助

37

这也值得一读:结构化单元测试

该结构每个要测试的类都有一个测试类。那不是很不寻常。但是对我来说不寻常的是,他为每个要测试的方法都有一个嵌套类。

例如

using Xunit;

public class TitleizerFacts
{
    public class TheTitleizerMethod
    {
        [Fact]
        public void NullName_ReturnsDefaultTitle()
        {
            // Test code
        }

        [Fact]
        public void Name_AppendsTitle()
        {
            // Test code
        }
    }

    public class TheKnightifyMethod
    {
        [Fact]
        public void NullName_ReturnsDefaultTitle()
        {
            // Test code
        }

        [Fact]
        public void MaleNames_AppendsSir()
        {
            // Test code
        }

        [Fact]
        public void FemaleNames_AppendsDame()
        {
            // Test code
        }
    }
}

这就是为什么:

一方面,这是保持测试井井有条的好方法。方法的所有测试(或事实)都分组在一起。例如,如果使用CTRL + M,CTRL + O快捷方式折叠方法主体,则可以轻松扫描测试并像读取代码规范一样读取它们。

我也喜欢这种方法:

MethodName_StateUnderTest_ExpectedBehavior

因此,也许调整为:

StateUnderTest_ExpectedBehavior

因为每个测试都已经在嵌套类中


2
对于在Visual Studio中使用Resharper的测试运行程序的用户,他们使用8.x中的嵌套测试类修复了错误。从那时起,到目前为止,这已成为我的首选结构。
angularsen 2015年

使用MethodName_StateUnderTest_ExpectedBehavior方法使名称变长真的重要吗?如“ InitializeApiConfiguration_MissingApiKey_IllegalArgumentException”。这真的是一个很好的测试名称吗?
Portfoliobuilder19年

28

我倾向于使用MethodName_DoesWhat_WhenTheseConditions诸如此类的约定:

Sum_ThrowsException_WhenNegativeNumberAs1stParam

但是,我看到的很多东西是使测试名称遵循的单元测试结构

  • 安排
  • 法案
  • 断言

这也遵循BDD / Gherkin语法:

  • 给定
  • 什么时候
  • 然后

以以下方式命名测试: UnderTheseTestConditions_WhenIDoThis_ThenIGetThis

以您的示例为例:

WhenNegativeNumberAs1stParam_Sum_ThrowsAnException

但是,我确实更喜欢将要测试的方法名称放在首位,因为这样可以按字母顺序排列测试,也可以在VisStudio的成员下拉框中按字母顺序显示测试,并且将1个方法的所有测试组合在一起。


无论如何,我喜欢用下划线(而不是每个单词)将测试名称的主要部分分开,因为我认为这样可以更容易阅读和理解测试要点。

换句话说,我喜欢:Sum_ThrowsException_WhenNegativeNumberAs1stParam胜于Sum_Throws_Exception_When_Negative_Number_As_1st_Param


22

我确实像使用“ PascalCasing”的其他方法一样命名测试方法,而没有任何下划线或分隔符。我将方法的后缀测试省去了,因为它没有任何价值。该方法是一种测试方法,由属性TestMethod表示。

[TestMethod]
public void CanCountAllItems() {
  // Test the total count of items in collection.
}

由于每个Test类只能测试另一个类,因此我将该类的名称保留在方法名称之外。包含测试方法的类的名称类似于被测类,其后缀为“ Tests”。

[TestClass]
public class SuperCollectionTests(){
    // Any test methods that test the class SuperCollection
}

对于测试异常或无法执行的操作的方法,我在测试方法前加上单词Cannot

[TestMethod]
[ExpectedException(typeOf(ArgumentException))]
public void CannotAddSameObjectAgain() {
  // Cannot add the same object again to the collection.
}

我的命名会议基于Bryan Cook 的文章“ TDD技巧:测试命名约定和准则”。我发现这篇文章很有帮助。


1
+1链接到我的帖子-尽管没有必要在测试中使用“测试”前缀。确保您的测试指定了预期的行为。例如,CanRetrieveProperCountWhenAddingMultipleItems()
bryanbcook

2
我不喜欢它,因为它不包含预期的行为
约翰内斯·鲁道夫

5

第一组名称对我来说更容易理解,因为CamelCasing分隔单词,而下划线分隔命名方案的各个部分。

我也倾向于在函数名称或封闭的名称空间或类中的某些地方包括“测试”。


2
@Frank methodName = camelCase MethodName = PascalCase
Metro Smurf

@ metro-smurf:有趣的区别,我从未听说过PascalCase使用的术语,而且我已经做很长时间了。我只在Microsoft开发人员圈子中看到术语PascalCase,这是您的工作吗?
Frank Szczerba 09年

关于Pascal套管和Camel套管的历史(来自:Brad Abrams-blogs.msdn.com/brada/archive/2004/02/03/67024.aspx)...“在框架的初始设计中,我们花了数百个小时关于命名样式的辩论。为了促进这些辩论,我们创造了许多术语。与设计团队的关键成员Anders Heilsberg(Turbo Pascal的原始设计师)一起担任设计团队的关键成员,难怪我们选择了Pascal Casing作为表壳样式通过Pascal编程语言进行了普及。”
直升机

-3

只要您遵循一种练习,就没关系了。通常,我为一个方法编写一个单元测试,以涵盖该方法的所有变体(我有简单的方法;),然后为需要该方法的方法编写更复杂的测试集。因此,我的命名结构通常是测试(来自JUnit 3的保留)。


-8

我将“ T”前缀用于测试名称空间,类和方法。

我尝试保持整洁,并创建用于复制名称空间的文件夹,然后为测试创建测试文件夹或单独的项目,并为基本测试复制生产结构:

AProj
   Objects
      AnObj
         AProp
   Misc
      Functions
         AFunc
   Tests
      TObjects
         TAnObj
            TAnObjsAreEqualUnderCondition
      TMisc
         TFunctions
            TFuncBehavesUnderCondition

我可以很容易地看到某种东西是一个测试,我确切地知道它与什么原始代码有关((如果您无法解决这个问题,那么无论如何该测试都太复杂了)。

看起来就像接口命名约定,(我的意思是,您不会与以“ I”开头的内容混淆,也不会与“ T”开头的内容混淆)。

带有或不带有测试的编译都很容易。

无论如何,从理论上讲,它是很好的,并且对于小型项目来说效果很好。


3
有趣的方法。有人可能会说T前缀与您在泛型中使用的约定(例如func(T1,T2,TResult))相冲突,但是我个人并不关心,只要团队内部达成共识即可。名称简短,这也使内容更具可读性。
刺痛

对我来说太匈牙利了(符号)。同样,ad stung指出,前缀T用于泛型类型参数。
Danny Varod 2011年

我同意,匈牙利符号已被贬义,并且由于与标准泛型类型参数的冲突,在这种情况下,我看不到有例外(例如,对于接口而言)。
SonOfPirate 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.