JavaScript 面试题
目录

请解释 Mock 和 Stub 的概念和区别。

· 约 6 分钟读完 · 第 258 / 507 章

推荐答案

Mock (模拟对象):

  • 定义: Mock 是一个模拟的对象,它完全替代了真实的对象,并且可以预先设定其行为和返回值。
  • 用途: 主要用于测试,特别是单元测试。通过 Mock 可以隔离被测试代码与外部依赖,使得测试更加专注于被测单元的逻辑。Mock 对象允许你验证交互,例如方法是否被调用、调用次数、以及参数等。
  • 行为: Mock 对象通常包含预先定义的行为,例如当某个方法被调用时,返回特定的值或者抛出特定的异常。
  • 重点: 强调验证交互和模拟复杂行为。

Stub (桩对象):

  • 定义: Stub 也是一个模拟对象,它提供预先设定的、简单的返回值或行为。
  • 用途: 主要用于测试,同样用于隔离被测试代码与外部依赖,但更侧重于提供测试所需的依赖。
  • 行为: Stub 专注于提供特定的返回值,以便被测代码能够按照预期的方式执行。它不关心被调用了多少次或使用了什么参数。
  • 重点: 强调提供预期的返回值,较少关注交互验证。

主要区别:

特性 Mock Stub
目的 模拟复杂行为,验证交互(调用、参数等) 提供预定义的返回值或行为,辅助测试
验证 可以验证方法的调用和参数 通常不验证方法的调用和参数
行为 更加灵活,可以定义复杂的行为 行为相对简单,主要返回预定义的值

本题详细解读

Mock 的详细解释

Mock 对象是一种功能更强大的模拟对象。在单元测试中,我们通常会遇到被测试的单元依赖于其他模块或服务的情况,例如数据库、API接口、其他模块的方法等。为了避免测试的复杂性和依赖性,我们使用 Mock 对象来模拟这些依赖,让测试更加简单、快速且稳定。

Mock 对象不仅可以模拟依赖的行为,还可以验证被测单元与这些依赖的交互。例如,我们可以设置一个 Mock 对象,当被测代码调用它的某个方法时,返回特定的值。我们还可以验证这个方法是否被调用了,被调用了多少次,调用时传递了什么参数。

例如:

假设我们有一个UserService类,依赖于UserRepository类:

在测试UserService时,我们可以使用 Mock 对象来模拟 UserRepository:

在这个例子中,jest.fn() 创建了一个 Mock 函数。我们设置了这个 Mock 函数的返回值,并验证了它是否被调用,被调用时传递的参数。

Stub 的详细解释

Stub 对象是一个简化的模拟对象,它主要用于提供预定义的返回值。与 Mock 不同,Stub 对象通常不用于验证交互,而是侧重于为被测代码提供必要的输入,使其能够正常执行。

Stub 对象通常用于简化依赖,并控制依赖的行为,从而使得测试能够专注于被测单元的核心逻辑。它减少了测试的复杂性,并使得测试更加可靠。

例如:

继续上面的UserService例子,我们用Stub来模拟 UserRepository:

在这个例子中,userRepositoryStub是一个Stub,它只负责返回预定的值,而没有像Mock一样验证getUserById的调用。

总结

Mock 和 Stub 都是用于测试的模拟对象,但侧重点不同。Mock 侧重于验证交互和模拟复杂行为,而 Stub 则侧重于提供预定义的返回值或行为。在实际测试中,我们可以根据需要选择合适的模拟对象类型。