何时使用单元测试框架(仅使用断言)?

时间:2010-02-01 21:01:45

标签: unit-testing tdd

使用一个小的(目前在150个位置,完成时可能少于500个)我正在研究的C项目,我正在自学测试驱动开发。基于我在网络上找到的一些东西 - 特别是these slides by Olve Maudal,我刚刚在我的单元测试中使用了断言。

由于我刚刚学习tdd,到目前为止我还避免了学习单元测试框架(如cunit)的开销。在这一点上,我的想法是,框架的额外学习曲线 - 即使是浅薄的 - 对于这样一个小项目来说是不值得的。我想知道:这是不正确的(即我现在更好地学习框架)?在什么时候学习框架会得到回报?

6 个答案:

答案 0 :(得分:6)

学习单元测试框架的收支平衡时间不长。使用assert()函数的框架获得的两个主要优点是

  • 断言失败的更详细信息:预期与实际值
  • 执行所有测试用例代替在第一次失败的断言时停止

其中两个给出了关于错误所在位置的提示。

答案 1 :(得分:3)

根据我学习.NET单元测试框架的经验,我几乎从一个小项目开始,然后给了我优势,能够将我学到的知识应用到其他项目中,无论其大小如何。

我猜你可能在想什么是重点,现在只是一小部分代码,但是我认为你现在可以很好地进入框架而不是之后。这有点像开车 - 我17岁的时候就开始学习驾驶,但直到两年后我才买到自己的车。我本来可以忽略上课,直到我开车,但我通过并且已经掌握了继续开车的技能。

有点奇怪的比喻,但这就是我在学习像框架或图书馆这样的东西时的想法 - 你根本不知道它会为你派上用场。

答案 2 :(得分:1)

学习xUnit框架 - 当您开始编写更大规模的商业项目时,您会发现它们被广泛使用。

答案 3 :(得分:1)

  

由于我刚刚学习tdd,到目前为止我还避免了学习单元测试框架(如cunit)的开销。在这一点上,我的想法是,框架的额外学习曲线 - 即使是浅薄的 - 对于这样一个小项目来说是不值得的。我想知道:这是不正确的(即我现在更好地学习框架)?在什么时候学习框架会得到回报?

我同意philippe,Jason和Paolo的意见,但又想进入另一种看待它的方式:

所谓的xUnit框架是非常简单明了,作为下载库(例如最新的JUnit或CUnit的二进制文件大约200千字节),还有更多从概念上来说,这是一种冒险的

如果您正在做(或想做)任何单元测试,您肯定会受益于使用经过验证的工具,并且学习xUnit将立即开始付款。我认为你可能过高估计了涉及的“开销” - 不要让“框架”这个词吓到你;-) - 你将在半小时或更短时间内使用xUnit运行。

免责声明:您的问题未标记为C,因此我将其视为与语言无关的问题。我不知道C端的单元测试是否非常不同(与Java相比),但我对此表示怀疑。 : - )功能

答案 4 :(得分:1)

以下是一个C#.Net示例,其中Moq framework在使用Visual Studio的MSTest中很有用。

观察TestOld()MoqTest()之间的区别。两个测试的目的是相同的。但在TestOld()中,我需要编写MyMemberManagerForTest具体实现。而在MoqTest()中,Moq框架将为我完成任务。

  _mockIMemberManager = new Mock<IMemberManager>();
  _mockIMemberManager.Setup(x => x.GetMember(It.IsAny<int>())).Returns(member);

参考:How to Use Mock Library For Your Unit Testing In C#

[TestClass()]
public class TestMembershipManager
{
    private LibraryCore _targetLibraryCore;

    #region Old Test withou Moq

    public class MyMemberManagerForTest : IMemberManager
    {
        public Member GetMember(int memberID)
        {
            Member member = new Member()
            {
                MemberID = 1,
                FirstName = "Lijo",
                MaximumBookCanBorrow = 4,
            };

            return member;
        }
    }

    private IMemberManager _memberManager;

    [TestMethod()]
    public void TestOld()
    {
        _memberManager = new MyMemberManagerForTest();
        _targetLibraryCore = new LibraryCore(_memberManager);

        int memberID = 1;
        double expected = 12;
        double actual;

        //TEST
        actual = _targetLibraryCore.CalculateMembershipCost(memberID);
        Assert.AreEqual(expected, actual);
    }


    #endregion

    #region Test with Moq
    private Mock<IMemberManager> _mockIMemberManager;

    [TestMethod()]
    public void MoqTest()
    {
        _mockIMemberManager = new Mock<IMemberManager>();
        _targetLibraryCore = new LibraryCore(_mockIMemberManager.Object);

        Member member = new Member()
        {
            MemberID = 1,
            FirstName = "Lijo",
            MaximumBookCanBorrow = 4,
        };

        _mockIMemberManager.Setup(x => x.GetMember(It.IsAny<int>())).Returns(member);

        int memberID = 1;
        double expected = 12;
        double actual;

        //TEST
        actual = _targetLibraryCore.CalculateMembershipCost(memberID);
        Assert.AreEqual(expected, actual);
    }

    #endregion

}

要使这种类型的测试正常工作,重要的是代码可以使用Dependency Injection,正如您在重载的LibraryCore构造函数中看到的那样

public class LibraryCore
{
    private readonly IMemberManager _memberManager;

    public LibraryCore(IMemberManager memberManager)
    {
        this._memberManager = memberManager;
    }

    public double CalculateMembershipCost(int memberID)
    {
        double membershipCost = 0;
        Member member = _memberManager.GetMember(memberID);
        membershipCost = 10 + member.MaximumBookCanBorrow * 0.5;
        return membershipCost;
    }
}

答案 5 :(得分:0)

一个注意事项:如果您遵循红绿重构的正常模式,那么当您重构单元测试时,结果代码应该演变为单元测试框架。例如,您不应该有两个代码副本

if (expected != actual) {printf("%d != %d", actual, expected); return -1;}

应该重构为

之类的东西
void AssertNotEqual(int expected, int actual, char* message)
{
    if (expected != actual) {printf(message, actual, expected); return -1;}
}