Vitest: 我如何模拟被测试函数使用的函数?

huangapple go评论76阅读模式
英文:

Vitest: How can I mock a function that the function being tested uses?

问题

Here is the translated code portion:

例如我如何模拟 `hello` 函数并使用 `.mockReturnValue("Hi")`希望有人能协助解决这个简单的示例因为我目前对此感到相当困惑

// greet.ts
export function hello() {
  return "Hello ";
}

export function greet(name: string) {
  return hello() + name;
}

测试文件:
// greet.spec.ts
import { hello, greet } from "./greet";

vi.mock("./greet", async () => {
  const mod = await vi.importActual<typeof import("./greet")>("./greet");
  const hello = vi.fn().mockReturnValue("Hi ");
  return {
    ...mod,
    hello,
    // greet: vi.fn((name: string) => hello() + name),
    // ^如果我取消注释,这将起作用,但这违背了测试的目的。
    // 我是否无法做到我想要的?
  };
});

describe("Greeting", () => {
  test("should return a personalized greeting", async () => {
    const result = greet("John");

    expect(result).toBe("Hi John");
    expect(hello).toHaveBeenCalled();
  });
});

Is there anything else you need assistance with?

英文:

For example, how can I mock the hello function and .mockReturnValue(&quot;Hi&quot;)? Hoping someone can assist with this simple example as it's quite confusing to me currently.

// greet.ts
export function hello() {
  return &quot;Hello &quot;;
}

export function greet(name: string) {
  return hello() + name;
}

Test file:

// greet.spec.ts
import {hello, greet} from &quot;./greet&quot;;

vi.mock(&quot;./greet&quot;, async () =&gt; {
  const mod = await vi.importActual&lt;typeof 
    import(&quot;./greet&quot;)&gt;(&quot;./greet&quot;);
  const hello = vi.fn().mockReturnValue(&quot;Hi &quot;);
  return {
    ...mod,
    hello,
    // greet: vi.fn((name: string)=&gt; hello() + name),
    // ^this works if I uncomment it, but it defeats 
    // the purpose of the test. 
    // Is it just not possible to do what I want? 
  }
})

describe(&quot;Greeting&quot;, () =&gt; {
  test(&quot;should return a personalized greeting&quot;, async () =&gt; {
    const result = greet(&quot;John&quot;);

    expect(result).toBe(&quot;Hi John&quot;);
    expect(hello).toHaveBeenCalled();
  });
});

Running the test still gives Hello John and the hello function is not called. No surprise... how can I mock the implementation of hello() in the actual greet function?

答案1

得分: 0

你可能是指mock()而不是doMock()doMock()不像mock()那样进行提升,这意味着当模拟生效时,已经为时过晚,因为真正的./greet已经在内存中,因为它在顶部导入。

虽然这个错误会阻止在这种情况下完全应用您的模拟,但很明显,在当前形式下,您试图从根本上实现的目标实际上是不可能的。

如果您使用某个模拟函数模拟hello,在测试中调用hello当然会调用该模拟函数。但是,由其他导出方法greet调用的hello版本仍将保持为原始的未模拟版本。

模拟不会改变“真正”的模块。它们几乎可以视为真实事物的代理。在内部,模块对于您的模拟一无所知。

一开始这样做可能会看起来很奇怪,但摆脱这种情况的通常方法不是尝试找到适用于现有代码的一些巧妙的解决方法,而是改变您的代码架构以使其更具可测试性。通常,使代码更具可测试性会导致更高质量的代码。

您的情况是一个不是“真实”的测试用例,因此很难建议一种最佳实践来对问题进行建模,使其具有可测试性,尽管为了避免重复之前的答案,一些示例模式可以在此答案中找到。

英文:

You probably meant mock() and not doMock(). doMock() doesn't do the hoisting that mock() does which means by the time the mock takes effect it's too late since the real ./greet is already in memory as it's imported at the top.

Whilst this bug would prevent your mock from applying entirely in this situation, it's also clear what you are trying to fundamentally achieve isn't really possible with the code architecture in its current form.

If you mock hello with some mock function, calling hello in the test will of course call that mock. However, the version of hello called by the other exported method greet will remain as the original un-mocked one.

Mocks don't mutate the "real" module. They can be viewed almost as a proxy for the real thing. Internally, the module has no idea about your mock.

It can at first seem odd to do this, but the usual way out of this situation isn't to try to find some hacky workaround that works with the existing code, but to instead change your code architecture to be more testable. Usually, making code more testable leads to higher-quality code.

Your case is a test case that's not "real" so it's very hard to recommend a best practice for modelling the problem which is testable, though to avoid repeating previous answers, some example patterns are available on this answer.

huangapple
  • 本文由 发表于 2023年6月9日 08:28:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76436481.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定