🔰

【Vue Test Utils】mountとshallowMountの違いと使い分け

に公開

mountとshallowMountの違い

mount

指定したVueコンポーネントの子コンポーネントまでを全てレンダリングするAPI。

import { mount } from '@vue/test-utils';
import ParentComponent from '@/components/ParentComponent.vue';

const wrapper = mount(ParentComponent);
console.log(wrapper.html());

出力例

<div>
  <h1>Parent Component</h1>
  <div>
    <p>Child Component Content</p>
  </div>
</div>

shallowMount

指定したVueコンポーネントをレンダリングするAPI。子コンポーネントはスタブ化される。

import { shallowMount } from '@vue/test-utils';
import ParentComponent from '@/components/ParentComponent.vue';

const wrapper = shallowMount(ParentComponent);
console.log(wrapper.html());

出力例

<div>
  <h1>Parent Component</h1>
  <child-component-stub></child-component-stub>
</div>

mountとshallowMountの使い分け

公式ドキュメントには以下の記述があります。以下、日本語訳です。

https://test-utils.vuejs.org/guide/advanced/stubs-shallow-mount#mount-shallow-and-stubs-which-one-and-when-

mount、shallow、stubs:それぞれの使いどころ
経験則として、テストがソフトウェアの使用方法に似ているほど、より自信を持てる結果を得られます。

mount を使用したテストは、全てのコンポーネント階層をレンダリングし、実際のブラウザでのユーザー体験に近くなります。

一方、shallow を使用したテストは特定のコンポーネントに焦点を当てています。shallow は、複雑なコンポーネントを完全に分離してテストする場合に有用です。テストに関連しないコンポーネントが1つか2つだけある場合は、shallow の代わりに mount と stubs の組み合わせを検討してください。stubs を多用するほど、本番環境に近いテストからは遠ざかります。

完全な mount か shallow レンダリングかに関わらず、良いテストは入力(propsやユーザーインタラクション、例えば trigger を使ったもの)と出力(レンダリングされたDOM要素やイベント)に焦点を当て、実装の詳細には注目しないことを覚えておいてください。

したがって、どのマウント方法を選ぶにしても、これらのガイドラインを念頭に置くことをお勧めします。

内容を要約すると、以下マウント方法がここでは提案されています。

  • mount:全コンポーネント階層をレンダリングし、ブラウザでのユーザー体験に近いテストが可能
  • shallowMount:特定のコンポーネントに焦点を当て、複雑なコンポーネントを完全に分離してテストする場合に有用
  • mount と stubs の組み合わせ:テストに関連しないコンポーネントが1つか2つだけある場合は、そのコンポーネントをスタブ化し、本番環境に近いテストを維持

このガイドラインに沿いつつ、効率性観点も考慮すると、shallowMountを優先して使い、shallowMountでは対処しづらいケースが発生した場合に、mountとstubsの組み合わせmountのみの使用 の順でテストが実現できないか検討する方針が良さそうだと思いました。

私好みのマウント方法(自論)

上述のガイドラインのやり方には含まれていませんが、自論としては shallowMountのみを基本的に使い、指定したコンポーネントのスタブ化をやめる形でマウントするのが好みの書き方です。
理由は、必要な箇所だけ実際のコンポーネントに置き換えるやり方はスタブ化の漏れが発生しづらく、テストの効率性を保ちやすいためです。

shallowMountを使い、指定したコンポーネントのスタブ化をやめる方法は公式ドキュメントでも案内されています。
指定したコンポーネントを明示的にスタブ化しないようにしたい場合は、stubsオプションで該当コンポーネントをfalseに設定することで実現できます。

https://test-utils.vuejs.org/guide/advanced/stubs-shallow-mount.html#Stubbing-all-children-components-with-exceptions

const ComplexA = {
  template: '<h2>Hello from real component!</h2>'
}

const ComplexComponent = {
  components: { ComplexA, ComplexB, ComplexC },
  template: `
    <h1>Welcome to Vue.js 3</h1>
    <ComplexA />
    <ComplexB />
    <ComplexC />
  `
}
test('shallow allows opt-out of stubbing specific component', () => {
  const wrapper = shallowMount(ComplexComponent, {
    global: {
      stubs: { ComplexA: false }
    }
  })

  console.log(wrapper.html())
  /*
    <h1>Welcome to Vue.js 3</h1>
    <h2>Hello from real component!</h2>
    <complex-b-stub></complex-b-stub>
    <complex-c-stub></complex-c-stub>
  */
})

※公式ドキュメントではmountとshallowオプションを併用していますが、この書き方はshallowMountと同義です
https://test-utils.vuejs.org/guide/advanced/stubs-shallow-mount.html#Stubbing-all-children-components:~:text=If you used VTU V1%2C you may remember this as shallowMount. That method is still available%2C too - it's the same as writing shallow%3A true

Discussion