使用一个小的(目前在150个位置,完成时可能少于500个)我正在研究的C项目,我正在自学测试驱动开发。基于我在网络上找到的一些东西 - 特别是these slides by Olve Maudal,我刚刚在我的单元测试中使用了断言。
由于我刚刚学习tdd,到目前为止我还避免了学习单元测试框架(如cunit)的开销。在这一点上,我的想法是,框架的额外学习曲线 - 即使是浅薄的 - 对于这样一个小项目来说是不值得的。我想知道:这是不正确的(即我现在更好地学习框架)?在什么时候学习框架会得到回报?
答案 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;}
}