何时使用存根和模拟?
我一直有这样的困惑。如果我编写一个使用假代码来断言某些操作的代码,那么当它真正使用真实对象而不是假对象启动时,我如何信任我的真实实现。
例如,我有这段代码——
[Test]
public void CanCreateContactsWithData()
{
using(ISession session = factory.OpenSession())
using (ITransaction trans = session.BeginTransaction())
{
_contactId = (long) session.Save(contact);
trans.Commit();
}
Assert.AreNotEqual(0, _contactId);
}
这段代码测试“联系人”对象的实现,无论该对象是否保存到数据库中。如果我碰巧使用存根而不是真正的数据库连接,我是否需要进行单独的测试以将其存储在数据库中?而且,你们称之为集成测试吗?
衷心感谢您的回答。
I've this confusion all the time. If I write a code which uses fake code to assert some operation, how do i trust my real implementation when it is started really using the real objects instead of fake ones.
For example, I've this code --
[Test]
public void CanCreateContactsWithData()
{
using(ISession session = factory.OpenSession())
using (ITransaction trans = session.BeginTransaction())
{
_contactId = (long) session.Save(contact);
trans.Commit();
}
Assert.AreNotEqual(0, _contactId);
}
This code tests the implementation of a "contact" object whether that gets saved into database or not. If i happened to use a stub instead of a real database connection, do I need to have separate test for storing it in database? And, do you guys call that as integration testing?
Answers are sincerely appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Martin Fowler 在此处进行了很好的讨论。
来自他的文章:
Meszaros 使用术语“测试替身”作为用于代替真实对象进行测试目的的任何类型假装对象的通用术语。这个名字来源于电影中特技替身的概念。 (他的目标之一是避免使用任何已经广泛使用的名称。)Meszaros 然后定义了四种特殊类型的 double:
在这些类型的双打中,只有模拟坚持行为验证。
Martin Fowler has a good discussion here.
From his article:
Meszaros uses the term Test Double as the generic term for any kind of pretend object used in place of a real object for testing purposes. The name comes from the notion of a Stunt Double in movies. (One of his aims was to avoid using any name that was already widely used.) Meszaros then defined four particular kinds of double:
Of these kinds of doubles, only mocks insist upon behavior verification.
当您只想让函数返回一些值(或不执行任何操作)时,可以使用存根。您并不真正关心该函数是否被调用,您只是想隔离事物。
模拟更强大,因为您还可以跟踪函数是否被调用、调用了多少次,甚至可以使用函数获取的值进行操作。
在您的情况下,如果您想模拟数据库(因此它成为单元测试而不是功能测试),您可以模拟 ISession 和 ITransaction。然后,您可以将此值存储在内存中,并检查是否保存了正确的值。
You use stubs when you just want a function to return some value (or do nothing). You don't really care if the function was called or not, you just want to isolate things.
Mocks are more powerful, as you can also keep track if the function was called, how many times, and even do things with values your function gets.
In your case, if you want to mock the database (so it becomes a unit test rather than a functional one), you can mock ISession and ITransaction. You could then store this values in-memory, and check if the correct values were saved.
您应该测试您编写的代码。如果您编写了数据库连接对象代码,请对其进行测试。否则,如果它是具有自己测试的库的一部分,您可以模拟/存根它并假设如果连接对象通过了它自己的测试套件,那么它就可以工作。
例如,我不会测试对 Hibernate 方法的调用,我假设 Hibernate 开发人员已经对此进行了彻底的测试。但我会测试我是否调用了正确的方法,使用模拟来设置该期望。
You should be testing the code that you have written. If you wrote the database connection object code, then test it. Otherwise if it is part of a library with it's own tests, you can just mock/stub it and assume that if the connection object passes it's own test suite, then it works.
For example, I wouldn't test calls to Hibernate methods, I assume the Hibernate developers have thoroughly tested that already. But I would test that I was calling the correct method, using a mock to set up that expectation.
是的,使用真实的数据库会更具功能性或集成测试,具体取决于您的定义。就我个人而言,我认为单元测试应该只测试该方法,而与其他所有内容隔离。因此,无论会话或事务是否有效,您的单元测试都必须确保这些对象将在必要时被调用来完成其工作 - 这就是模拟和存根的用武之地。使用它们来确保您的单元测试与外部功能解耦,以便可以将其作为基本单元进行测试;无论如何,理想情况下。
Yes, using a real database would be more functional or integration testing, depending on your definition. Personally, I feel that unit tests are supposed to test exactly that method only, in isolation of everything else. So regardless of whether the session or the transaction works or not, your unit test must ensure that those objects will be called upon to do their work when and as necessary - that's where mocks and stubs come in. You use them to ensure that your unit test is as decoupled from external functionality so that it can be tested as a basic unit; ideally anyway.
大多数类型的单元测试都是关于测试各个代码段,而存根和模拟只是帮助您逐段测试的工具。通过单独测试各个部分,您可能可以更详细地测试每个部分,但不能保证您的整体情况。各种集成测试都可以做到这一点。
当测试较大的功能时,我经常发现数据库逻辑的实际集成测试是最不有价值的测试工件,因为您通常会在 UI 级别测试这些相同的操作。
Most kinds of unit testing is about testing individual pieces of code, and stubs and mocks are simply tools that assist you in testing piece-by-piece. By testing pieces individually you can probably test each piece in greater detail, but you will not be guaranteed anything about the full picture. Various kinds of integration testing will do that.
When testing bigger pieces of functionality, I often find actual integration tests of database logic to be the least valuable test artifacts, since you will often be testing these same operations at the UI level.