您应该在每个“test()/it()”块中还是在全局中渲染组件/选择元素?

hen*_*enk 3 reactjs jestjs react-testing-library

react-testing-library对其元素执行一些测试之前,您必须渲染您的反应组件。

  1. 对于同一组件的多次测试,是否应该避免多次渲染该组件?或者你必须在每个 test()/it()块中渲染它?

  2. 您应该选择每个块中的组件元素(例如按钮)test()/it(),还是应该取消选择并仅选择一次?

  3. 它对测试的执行时间有影响吗?

  4. 其中一种方法是最佳实践/反模式吗?

  5. 为什么最后一个例子失败了?

对于基本组件我有以下测试方法:

function MyComponent() {
  return (
    <>
      <button disabled>test</button>
      <button disabled>another button</button>
    </>
  );
}
Run Code Online (Sandbox Code Playgroud)

例如

describe("MyComponent", () => {
  it("renders", async () => {
    const { getByRole } = render(<MyComponent />);
    const button = getByRole("button", { name: /test/i });
    expect(button).toBeInTheDocument();
  });

  it("is disabled", async () => {
    // repetetive render and select, should be avoided or adopted?
    const { getByRole } = render(<MyComponent />);
    const button = getByRole("button", { name: /test/i });
    expect(button).toBeDisabled();
  });
});
Run Code Online (Sandbox Code Playgroud)

describe("MyComponent", () => {
  const { getByRole } = render(<MyComponent />);
  const button = getByRole("button", { name: /test/i });

  it("renders", async () => {
    expect(button).toBeInTheDocument();
  });

  it("is disabled", async () => {
    expect(button).toBeDisabled();
  });
});
Run Code Online (Sandbox Code Playgroud)

我希望第二种方法具有更快的执行时间,因为组件只需渲染一次,但我不知道如何测量它以及它是否是反模式?虽然它看起来更DRY,但如果我添加另一个toBeInTheDocument检查,它就会失败。

为什么会这样呢?

describe("MyComponent", () => {
  const { getByRole } = render(<MyComponent />);
  const button = screen.getByRole("button", { name: /test/i });
  const button2 = screen.getByRole("button", { name: /another button/i });
  
  it("renders", async () => {
    expect(button).toBeInTheDocument(); //ok
  });

  it("is disabled", async () => {
    expect(button).toBeDisabled(); // ok
  });

  it("renders second button", async () => {
    expect(button2).toBeInTheDocument(); // fails: element could not be found in the document
  });
});
Run Code Online (Sandbox Code Playgroud)

那么这种做法似乎更容易出错!?

Ovi*_*nas 5

每个测试都应该尽可能原子,这意味着它不应该使用其他测试也在使用的任何东西,并且应该以新的状态运行。因此,将其与您的示例联系起来,第一个是正确的模式。

当您的测试套件包含单元测试之间可共享的状态(例如对象或环境变量)时,测试套件很容易出错。原因是;如果单元测试之一碰巧改变了共享对象之一;所有其他单元测试也将受到此影响,导致它们表现出不需要的行为。这可能会导致测试失败,而代码在技术上是正确的,甚至为未来的开发人员埋下地雷,添加正确的新测试仍然会导致失败,从而在弄清楚为什么会发生这种情况时造成重大麻烦。

此规则的唯一例外是不可变的原始变量(例如string,使用关键字),因为测试将无法改变它们,并且它们对于存储可重用的 ID、文本等很有用numberbooleanconst

当然,重复每个单元测试的设置可能会让它们变得非常笨重,这就是为什么jest提供beforeEachbeforeAllafterEachafterAll函数来提取重复逻辑。但是,这会带来共享状态的漏洞,因此请务必小心并确保在开始任何测试之前刷新所有状态。参考

对于最后一个问题,即为什么上一个示例中的最后一个单元测试失败 - 看来您正在使用getByRole查找按钮文本。你应该改用getByText。与您似乎没有使用的属性(例如)getByRole一起使用。role<button role="test">test</button>