9

我从自动化测试开始,我想测试我的一种数据访问方法。如果数据库没有返回记录,我正在尝试测试代码的作用。

这是应该在单元测试或集成测试中完成的事情吗?

谢谢

4

10 回答 10

15

如果您的测试代码连接到实际数据库并依赖于某些数据的存在(或缺少数据)以使测试通过,那么它就是一个集成测试。

我通常更喜欢通过模拟“数据访问方法”用于获取实际数据的组件来测试类似的东西,无论是 JDBC 连接还是 Web 服务代理或其他任何东西。使用mock,你说“当这个方法被调用时,返回这个”或者“确保这个方法被调用N次”,然后你告诉被测类使用mock组件而不是真正的组件。这是一个“单元测试”,因为您正在测试被测类的行为方式,在一个封闭的系统中,您已经准确地声明了其他组件的行为方式。您已经完全隔离了被测类,并且可以确保您的测试结果不会波动并且依赖于另一个组件的状态。

不确定您使用的是什么语言/技术,但在 Java 世界中,您可以为此目的使用 JMock、EasyMock 等。

于 2009-02-05T16:16:19.780 回答
10

我认为更多的时间浪费在争论什么是单元与什么是集成测试而不是增加价值。

我不在乎。

让我换一种说法:如果我在测试它,我会看到两种方法 - 伪造返回零行的数据库,或者实际连接到没有数据可供选择的数据库。我可能会从最容易做和最容易实施的任何事情开始测试——如果它运行得足够快,我可以获得有意义的反馈。如果我需要它跑得更快或者认为会有一些优势,我会考虑另一个。

例如,我可能会在我的工作中开始连接到实际的测试数据库。但是如果软件需要与许多不同的数据库一起工作——Oracle、PostGres、MySQL、SQL 服务器和数据库,或者如果工作中的测试数据库因为“刷新”而停机,我可能会写“纯/单元”完全孤立存在的测试。

在我晚年,我更喜欢更频繁地使用“面向开发人员”和“面向客户”这个词,并进行更有意义的测试。我发现广泛使用诸如“单元”之类的术语,然后得到一个关于它的定义会导致人们做一些事情,比如模拟文件系统或模拟 getter 和 setter——我觉得没有帮助的活动。

我坚信这一点;我已经在谷歌之前介绍过它。

http://www.google.com/url?sa=t&source=web&oi=video_result&ct=res&cd=1&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DPHtEkkKXSiY&ei=9-wKSobjEpKANvHT_MEB&rct=j&q=heusser+ GTAC+2007&usg=AFQjCNHOgFzsoVss50Qku1p011J4-UjhgQ

祝你好运!让我们知道怎么回事!

于 2009-05-13T15:53:50.307 回答
7

做你的测试,让其他人花时间研究分类学。

于 2009-02-05T16:13:29.237 回答
7

我的观点是,您应该根据范围对测试进行分类:

  • 单元测试可以独立运行,无需任何外部依赖项(文件 IO、网络 IO、数据库、外部 Web 服务)。
  • 集成测试可以触及外部系统。

如果测试需要运行真实的数据库,则将其称为集成测试并将其与单元测试分开。这很重要,因为如果您将集成和单元测试混合在一起,那么您的代码可维护性就会降低。

混合的测试包意味着新开发人员可能需要一大堆外部依赖项才能运行测试套件。想象一下,您想要更改与数据库相关但实际上并不需要数据库运行的一段代码,如果您需要一个数据库来运行与数据库相关的测试,您将会感到沮丧项目。

如果外部依赖项难以模拟(例如,在 DotNet 中,如果您使用 Rhino Mocks 并且外部类没有接口),则创建一个接触外部系统的瘦包装类。然后在单元测试中模拟出那个包装器。您不需要数据库来运行这个简单的测试,所以不需要数据库!

于 2009-02-05T17:02:52.383 回答
5

有些人(包括我自己)对单元测试与集成测试的构成有严格的规定。

如果满足以下条件,则测试不是单元测试

  • 它与数据库对话
  • 它通过网络进行通信
  • 它涉及文件系统
  • 它不能与您的任何其他单元测试同时运行
  • 你必须对你的环境做一些特殊的事情(比如编辑配置文件)才能运行它

例如,这可能是区分单元测试将为您使用模拟所做的事情的一种方法,而不是任何真正的资源提供者——文件系统、数据库等。

集成测试可以看成是系统/应用层耦合度很高的测试,所以基础测试是单元测试,系统互操作性是集成测试的重点。

尽管如此,它仍然是一个灰色地带,因为人们通常可以查明这些规则的某些例外情况。

于 2009-02-05T16:29:26.740 回答
2

我认为重要的问题是“我该做什么?”

在这种情况下我认为你应该进行单元测试。模拟与数据库对话的代码并让它返回一个可靠的结果(无行),这样你的测试会检查没有行时会发生什么,而不是当数据库返回数据库中的任何内容时会发生什么测试。

绝对是单元测试!

[TestMethod]
public void ForgotMyPassword_SendsAnEmail_WhenValidUserIsPassed()
{
    var userRepository = MockRepository.GenerateStub<IUserRepository>();
    var notificationSender = MockRepository.GenerateStub<INotificationSender>();
    userRepository.Stub(x => x.GetUserByEmailAddressAndPassword("me@home.com", "secret")).Return(new User { Id = 5, Name = "Peter Morris" });

    new LoginController(userRepository, notificationSender).ResendPassword("me@home.com", "secret");

    notificationSender.AssertWasCalled(x => x.Send(null),
        options => options.Constraints(Text.StartsWith("Changed")));
}
于 2009-02-05T16:43:50.643 回答
1

我相信可以在没有真实数据库的情况下将其作为单元测试进行测试。与其使用数据库的真实接口,不如用模拟/存根/假对象替换它(更好的可视化 PDF 在这里)。

如果将其编写为单元测试证明太难了,并且您无法重构代码以使其易于测试,那么您最好将其编写为集成测试。它会运行得更慢,因此您可能无法在代码更改后运行所有集成测试(与您可以每秒运行成百上千的单元测试不同),但只要它们定期运行(例如作为持续集成),它们会产生一些价值。

于 2009-02-05T16:26:42.237 回答
0

很可能是单元测试......但这里有一条模糊的线。这实际上取决于执行了多少代码 - 如果它包含在库或类中,那么它的单元测试,如果它跨越多个组件,那么它更像是一个集成测试。

于 2009-02-05T16:11:58.540 回答
0

我相信这应该在单元测试中完成。您没有测试它是否可以连接到数据库,或者您可以调用您的存储过程......您正在测试代码的行为。

我可能是错的,但这就是我的想法,除非有人给我一个不这样想的理由。

于 2009-02-05T16:12:09.770 回答
0

根据定义,这是一个单元测试:您正在测试特定路径上代码的单个隔离元素

于 2009-02-05T16:56:25.330 回答