[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fy91QiGlizC6okUIIwe6ET-O5HCBNd-sjB-wgMTrj0AU":3,"$fu6zfcA75JDaS3YjzfpX6tpUxtIrz40OAtRxYKs__ebI":1930},{"id":4,"title":5,"body":6,"date":1915,"description":1916,"extension":1917,"icon":1918,"meta":1919,"navigation":141,"ogImage":1920,"path":1921,"published":141,"publishedAt":1922,"seo":1923,"stem":1924,"tags":1925,"updatedAt":1922,"__hash__":1929},"tech/tech/mock-nuxt-import.md","Nuxt インポート関数をモックする mockNuxtImport 関数の紹介",{"type":7,"value":8,"toc":1909},"minimark",[9,14,26,30,58,61,75,506,509,627,634,1187,1195,1198,1209,1212,1875,1885,1888,1905],[10,11,13],"h2",{"id":12},"mocknuxtimport-とは","mockNuxtImport とは？",[15,16,17,21,22,25],"p",{},[18,19,20],"code",{},"mockNuxtImport"," とは、Nuxt のインポート関数たちをモックする ",[18,23,24],{},"@nuxt/test-utils"," が提供するユーティリティ関数です。",[27,28],"external-link-card-wrapper",{"url":29},"https://nuxt.com/docs/getting-started/testing#mocknuxtimport",[15,31,32,35,36,39,40,43,44,47,48,51,52,54,55,57],{},[18,33,34],{},"useAsyncData"," や ",[18,37,38],{},"useFetch"," のようなインポート関数は Nuxt の内部で ",[18,41,42],{},"#imports"," から自動的にインポートされているので通常の ",[18,45,46],{},"vi.mock()"," ではうまくモックできません。",[49,50],"br",{},"\nそのため、これらの関数をテスト中に差し替えたい場合は、",[18,53,24],{}," が提供する ",[18,56,20],{}," を使うと便利です。",[10,59,60],{"id":60},"実際に使ってみる",[15,62,63,64,67,68,70,71,74],{},"例えばこのような ",[18,65,66],{},"composables"," があるとします。",[49,69],{},"\n（実際には ",[18,72,73],{},"useAsyncDate"," で ユーザー API を Fetch している）",[76,77,83],"pre",{"className":78,"code":79,"filename":80,"language":81,"meta":82,"style":82},"language-ts shiki shiki-themes material-theme-lighter github-dark-high-contrast github-dark","type User = {\n  familyName: string\n  firstName: string\n}\n\nexport const useUser = async () => {\n  const { data: user } = await useAsyncData\u003CUser>(async () => {\n    return {\n      firstName: 'kohei',\n      familyName: 'tsukiyama',\n    }\n  })\n\n  const toDisplayName = () => {\n    if (user.value === null) {\n      throw new Error('User is Missing')\n    }\n    const firstName = user.value.firstName\n    const familyName = user.value.familyName\n    const fullName = [firstName, familyName].filter(Boolean).join(' ')\n    return fullName.toUpperCase()\n  }\n\n  return { user, toDisplayName }\n}\n","user.ts","ts","",[18,84,85,106,120,130,136,143,170,222,230,252,269,275,284,289,305,337,360,365,387,408,458,473,479,484,501],{"__ignoreMap":82},[86,87,90,94,98,102],"span",{"class":88,"line":89},"line",1,[86,91,93],{"class":92},"sGRfs","type",[86,95,97],{"class":96},"sywW5"," User",[86,99,101],{"class":100},"sUBcA"," =",[86,103,105],{"class":104},"seLpV"," {\n",[86,107,109,113,116],{"class":88,"line":108},2,[86,110,112],{"class":111},"s-3tI","  familyName",[86,114,115],{"class":100},":",[86,117,119],{"class":118},"snYqn"," string\n",[86,121,123,126,128],{"class":88,"line":122},3,[86,124,125],{"class":111},"  firstName",[86,127,115],{"class":100},[86,129,119],{"class":118},[86,131,133],{"class":88,"line":132},4,[86,134,135],{"class":104},"}\n",[86,137,139],{"class":88,"line":138},5,[86,140,142],{"emptyLinePlaceholder":141},true,"\n",[86,144,146,150,153,157,159,162,165,168],{"class":88,"line":145},6,[86,147,149],{"class":148},"stP2V","export",[86,151,152],{"class":92}," const",[86,154,156],{"class":155},"s8Xov"," useUser",[86,158,101],{"class":100},[86,160,161],{"class":92}," async",[86,163,164],{"class":104}," ()",[86,166,167],{"class":92}," =>",[86,169,105],{"class":104},[86,171,173,176,179,182,184,188,191,193,196,200,203,206,209,213,216,218,220],{"class":88,"line":172},7,[86,174,175],{"class":92},"  const",[86,177,178],{"class":104}," {",[86,180,181],{"class":111}," data",[86,183,115],{"class":104},[86,185,187],{"class":186},"sSuNx"," user",[86,189,190],{"class":104}," }",[86,192,101],{"class":100},[86,194,195],{"class":148}," await",[86,197,199],{"class":198},"s7KVs"," useAsyncData",[86,201,202],{"class":104},"\u003C",[86,204,205],{"class":96},"User",[86,207,208],{"class":104},">",[86,210,212],{"class":211},"sLCpo","(",[86,214,215],{"class":92},"async",[86,217,164],{"class":104},[86,219,167],{"class":92},[86,221,105],{"class":104},[86,223,225,228],{"class":88,"line":224},8,[86,226,227],{"class":148},"    return",[86,229,105],{"class":104},[86,231,233,236,238,242,246,249],{"class":88,"line":232},9,[86,234,235],{"class":211},"      firstName",[86,237,115],{"class":104},[86,239,241],{"class":240},"sPUPB"," '",[86,243,245],{"class":244},"sSIes","kohei",[86,247,248],{"class":240},"'",[86,250,251],{"class":104},",\n",[86,253,255,258,260,262,265,267],{"class":88,"line":254},10,[86,256,257],{"class":211},"      familyName",[86,259,115],{"class":104},[86,261,241],{"class":240},[86,263,264],{"class":244},"tsukiyama",[86,266,248],{"class":240},[86,268,251],{"class":104},[86,270,272],{"class":88,"line":271},11,[86,273,274],{"class":104},"    }\n",[86,276,278,281],{"class":88,"line":277},12,[86,279,280],{"class":104},"  }",[86,282,283],{"class":211},")\n",[86,285,287],{"class":88,"line":286},13,[86,288,142],{"emptyLinePlaceholder":141},[86,290,292,294,297,299,301,303],{"class":88,"line":291},14,[86,293,175],{"class":92},[86,295,296],{"class":155}," toDisplayName",[86,298,101],{"class":100},[86,300,164],{"class":104},[86,302,167],{"class":92},[86,304,105],{"class":104},[86,306,308,311,314,318,321,324,327,331,334],{"class":88,"line":307},15,[86,309,310],{"class":148},"    if",[86,312,313],{"class":211}," (",[86,315,317],{"class":316},"sdyPO","user",[86,319,320],{"class":104},".",[86,322,323],{"class":316},"value",[86,325,326],{"class":100}," ===",[86,328,330],{"class":329},"s4Pz2"," null",[86,332,333],{"class":211},") ",[86,335,336],{"class":104},"{\n",[86,338,340,343,346,349,351,353,356,358],{"class":88,"line":339},16,[86,341,342],{"class":148},"      throw",[86,344,345],{"class":100}," new",[86,347,348],{"class":198}," Error",[86,350,212],{"class":211},[86,352,248],{"class":240},[86,354,355],{"class":244},"User is Missing",[86,357,248],{"class":240},[86,359,283],{"class":211},[86,361,363],{"class":88,"line":362},17,[86,364,274],{"class":104},[86,366,368,371,374,376,378,380,382,384],{"class":88,"line":367},18,[86,369,370],{"class":92},"    const",[86,372,373],{"class":186}," firstName",[86,375,101],{"class":100},[86,377,187],{"class":316},[86,379,320],{"class":104},[86,381,323],{"class":316},[86,383,320],{"class":104},[86,385,386],{"class":316},"firstName\n",[86,388,390,392,395,397,399,401,403,405],{"class":88,"line":389},19,[86,391,370],{"class":92},[86,393,394],{"class":186}," familyName",[86,396,101],{"class":100},[86,398,187],{"class":316},[86,400,320],{"class":104},[86,402,323],{"class":316},[86,404,320],{"class":104},[86,406,407],{"class":316},"familyName\n",[86,409,411,413,416,418,421,424,427,429,432,434,437,439,442,445,447,450,452,454,456],{"class":88,"line":410},20,[86,412,370],{"class":92},[86,414,415],{"class":186}," fullName",[86,417,101],{"class":100},[86,419,420],{"class":211}," [",[86,422,423],{"class":316},"firstName",[86,425,426],{"class":104},",",[86,428,394],{"class":316},[86,430,431],{"class":211},"]",[86,433,320],{"class":104},[86,435,436],{"class":198},"filter",[86,438,212],{"class":211},[86,440,441],{"class":316},"Boolean",[86,443,444],{"class":211},")",[86,446,320],{"class":104},[86,448,449],{"class":198},"join",[86,451,212],{"class":211},[86,453,248],{"class":240},[86,455,241],{"class":240},[86,457,283],{"class":211},[86,459,461,463,465,467,470],{"class":88,"line":460},21,[86,462,227],{"class":148},[86,464,415],{"class":316},[86,466,320],{"class":104},[86,468,469],{"class":198},"toUpperCase",[86,471,472],{"class":211},"()\n",[86,474,476],{"class":88,"line":475},22,[86,477,478],{"class":104},"  }\n",[86,480,482],{"class":88,"line":481},23,[86,483,142],{"emptyLinePlaceholder":141},[86,485,487,490,492,494,496,498],{"class":88,"line":486},24,[86,488,489],{"class":148},"  return",[86,491,178],{"class":104},[86,493,187],{"class":316},[86,495,426],{"class":104},[86,497,296],{"class":316},[86,499,500],{"class":104}," }\n",[86,502,504],{"class":88,"line":503},25,[86,505,135],{"class":104},[15,507,508],{},"テンプレートはこんな感じです。",[76,510,515],{"className":511,"code":512,"filename":513,"language":514,"meta":82,"style":82},"language-vue shiki shiki-themes material-theme-lighter github-dark-high-contrast github-dark","\u003Cscript setup lang=\"ts\">\nconst user = await useUser()\n\u003C/script>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cp>{{ user.toDisplayName() }}\u003C/p>\n  \u003C/div>\n\u003C/template>\n","index.vue","vue",[18,516,517,545,560,569,573,582,592,610,619],{"__ignoreMap":82},[86,518,519,521,525,529,532,535,538,540,542],{"class":88,"line":89},[86,520,202],{"class":104},[86,522,524],{"class":523},"siCa7","script",[86,526,528],{"class":527},"sOohs"," setup",[86,530,531],{"class":527}," lang",[86,533,534],{"class":104},"=",[86,536,537],{"class":240},"\"",[86,539,81],{"class":244},[86,541,537],{"class":240},[86,543,544],{"class":104},">\n",[86,546,547,550,552,554,556,558],{"class":88,"line":108},[86,548,549],{"class":92},"const",[86,551,187],{"class":186},[86,553,101],{"class":100},[86,555,195],{"class":148},[86,557,156],{"class":198},[86,559,472],{"class":316},[86,561,562,565,567],{"class":88,"line":122},[86,563,564],{"class":104},"\u003C/",[86,566,524],{"class":523},[86,568,544],{"class":104},[86,570,571],{"class":88,"line":132},[86,572,142],{"emptyLinePlaceholder":141},[86,574,575,577,580],{"class":88,"line":138},[86,576,202],{"class":104},[86,578,579],{"class":523},"template",[86,581,544],{"class":104},[86,583,584,587,590],{"class":88,"line":145},[86,585,586],{"class":104},"  \u003C",[86,588,589],{"class":523},"div",[86,591,544],{"class":104},[86,593,594,597,599,601,604,606,608],{"class":88,"line":172},[86,595,596],{"class":104},"    \u003C",[86,598,15],{"class":523},[86,600,208],{"class":104},[86,602,603],{"class":316},"{{ user.toDisplayName() }}",[86,605,564],{"class":104},[86,607,15],{"class":523},[86,609,544],{"class":104},[86,611,612,615,617],{"class":88,"line":224},[86,613,614],{"class":104},"  \u003C/",[86,616,589],{"class":523},[86,618,544],{"class":104},[86,620,621,623,625],{"class":88,"line":232},[86,622,564],{"class":104},[86,624,579],{"class":523},[86,626,544],{"class":104},[15,628,629,630,633],{},"ちゃんと大文字になり名と姓の間に半角スペースが入るか、",[18,631,632],{},"toDisplayName"," のテストをしたいとします。",[76,635,638],{"className":78,"code":636,"filename":637,"language":81,"meta":82,"style":82},"import { mockNuxtImport } from '@nuxt/test-utils/runtime'\nimport { it, expect, describe, vi } from 'vitest'\nimport { useUser } from '../useAsyncData'\n\n// useAsyncData のモック関数を定義\nconst { useAsyncData } = vi.hoisted(() => {\n  return {\n    useAsyncData: vi.fn().mockImplementation(() => {\n      return { data: {} }\n    }),\n  }\n})\n\n// Nuxt の useAsyncData を上で作成したモックに置き換える\nmockNuxtImport('useAsyncData', () => {\n  return useAsyncData\n})\n\ndescribe('useUser', () => {\n  it('正常系 ユーザーデータが取得できる場合', async () => {\n    const mockUser = ref({\n      firstName: 'test',\n      familyName: 'user',\n    })\n    // モックの戻り値を定義\n    useAsyncData.mockResolvedValue({\n      data: mockUser,\n    })\n    const { toDisplayName } = await useUser()\n    expect(toDisplayName()).toBe('TEST USER')\n  })\n  it('異常系 ユーザーデータが取得できなかった場合', async () => {\n    useAsyncData.mockResolvedValue({\n      data: ref(null),\n    })\n    const { toDisplayName } = await useUser()\n    expect(() => toDisplayName()).toThrow('User is Missing')\n  })\n})\n\n","user.spec.ts",[18,639,640,663,698,717,721,727,755,761,790,806,815,819,826,830,835,855,862,868,872,894,918,934,949,963,969,974,988,1000,1007,1026,1055,1062,1086,1099,1117,1124,1143,1173,1180],{"__ignoreMap":82},[86,641,642,645,647,650,652,655,657,660],{"class":88,"line":89},[86,643,644],{"class":148},"import",[86,646,178],{"class":104},[86,648,649],{"class":316}," mockNuxtImport",[86,651,190],{"class":104},[86,653,654],{"class":148}," from",[86,656,241],{"class":240},[86,658,659],{"class":244},"@nuxt/test-utils/runtime",[86,661,662],{"class":240},"'\n",[86,664,665,667,669,672,674,677,679,682,684,687,689,691,693,696],{"class":88,"line":108},[86,666,644],{"class":148},[86,668,178],{"class":104},[86,670,671],{"class":316}," it",[86,673,426],{"class":104},[86,675,676],{"class":316}," expect",[86,678,426],{"class":104},[86,680,681],{"class":316}," describe",[86,683,426],{"class":104},[86,685,686],{"class":316}," vi",[86,688,190],{"class":104},[86,690,654],{"class":148},[86,692,241],{"class":240},[86,694,695],{"class":244},"vitest",[86,697,662],{"class":240},[86,699,700,702,704,706,708,710,712,715],{"class":88,"line":122},[86,701,644],{"class":148},[86,703,178],{"class":104},[86,705,156],{"class":316},[86,707,190],{"class":104},[86,709,654],{"class":148},[86,711,241],{"class":240},[86,713,714],{"class":244},"../useAsyncData",[86,716,662],{"class":240},[86,718,719],{"class":88,"line":132},[86,720,142],{"emptyLinePlaceholder":141},[86,722,723],{"class":88,"line":138},[86,724,726],{"class":725},"sZPSj","// useAsyncData のモック関数を定義\n",[86,728,729,731,733,735,737,739,741,743,746,748,751,753],{"class":88,"line":145},[86,730,549],{"class":92},[86,732,178],{"class":104},[86,734,199],{"class":186},[86,736,190],{"class":104},[86,738,101],{"class":100},[86,740,686],{"class":316},[86,742,320],{"class":104},[86,744,745],{"class":198},"hoisted",[86,747,212],{"class":316},[86,749,750],{"class":104},"()",[86,752,167],{"class":92},[86,754,105],{"class":104},[86,756,757,759],{"class":88,"line":172},[86,758,489],{"class":148},[86,760,105],{"class":104},[86,762,763,766,768,770,772,775,777,779,782,784,786,788],{"class":88,"line":224},[86,764,765],{"class":211},"    useAsyncData",[86,767,115],{"class":104},[86,769,686],{"class":316},[86,771,320],{"class":104},[86,773,774],{"class":198},"fn",[86,776,750],{"class":211},[86,778,320],{"class":104},[86,780,781],{"class":198},"mockImplementation",[86,783,212],{"class":211},[86,785,750],{"class":104},[86,787,167],{"class":92},[86,789,105],{"class":104},[86,791,792,795,797,799,801,804],{"class":88,"line":232},[86,793,794],{"class":148},"      return",[86,796,178],{"class":104},[86,798,181],{"class":211},[86,800,115],{"class":104},[86,802,803],{"class":104}," {}",[86,805,500],{"class":104},[86,807,808,811,813],{"class":88,"line":254},[86,809,810],{"class":104},"    }",[86,812,444],{"class":211},[86,814,251],{"class":104},[86,816,817],{"class":88,"line":271},[86,818,478],{"class":104},[86,820,821,824],{"class":88,"line":277},[86,822,823],{"class":104},"}",[86,825,283],{"class":316},[86,827,828],{"class":88,"line":286},[86,829,142],{"emptyLinePlaceholder":141},[86,831,832],{"class":88,"line":291},[86,833,834],{"class":725},"// Nuxt の useAsyncData を上で作成したモックに置き換える\n",[86,836,837,839,841,843,845,847,849,851,853],{"class":88,"line":307},[86,838,20],{"class":198},[86,840,212],{"class":316},[86,842,248],{"class":240},[86,844,34],{"class":244},[86,846,248],{"class":240},[86,848,426],{"class":104},[86,850,164],{"class":104},[86,852,167],{"class":92},[86,854,105],{"class":104},[86,856,857,859],{"class":88,"line":339},[86,858,489],{"class":148},[86,860,861],{"class":316}," useAsyncData\n",[86,863,864,866],{"class":88,"line":362},[86,865,823],{"class":104},[86,867,283],{"class":316},[86,869,870],{"class":88,"line":367},[86,871,142],{"emptyLinePlaceholder":141},[86,873,874,877,879,881,884,886,888,890,892],{"class":88,"line":389},[86,875,876],{"class":198},"describe",[86,878,212],{"class":316},[86,880,248],{"class":240},[86,882,883],{"class":244},"useUser",[86,885,248],{"class":240},[86,887,426],{"class":104},[86,889,164],{"class":104},[86,891,167],{"class":92},[86,893,105],{"class":104},[86,895,896,899,901,903,906,908,910,912,914,916],{"class":88,"line":410},[86,897,898],{"class":198},"  it",[86,900,212],{"class":211},[86,902,248],{"class":240},[86,904,905],{"class":244},"正常系 ユーザーデータが取得できる場合",[86,907,248],{"class":240},[86,909,426],{"class":104},[86,911,161],{"class":92},[86,913,164],{"class":104},[86,915,167],{"class":92},[86,917,105],{"class":104},[86,919,920,922,925,927,930,932],{"class":88,"line":460},[86,921,370],{"class":92},[86,923,924],{"class":186}," mockUser",[86,926,101],{"class":100},[86,928,929],{"class":198}," ref",[86,931,212],{"class":211},[86,933,336],{"class":104},[86,935,936,938,940,942,945,947],{"class":88,"line":475},[86,937,235],{"class":211},[86,939,115],{"class":104},[86,941,241],{"class":240},[86,943,944],{"class":244},"test",[86,946,248],{"class":240},[86,948,251],{"class":104},[86,950,951,953,955,957,959,961],{"class":88,"line":481},[86,952,257],{"class":211},[86,954,115],{"class":104},[86,956,241],{"class":240},[86,958,317],{"class":244},[86,960,248],{"class":240},[86,962,251],{"class":104},[86,964,965,967],{"class":88,"line":486},[86,966,810],{"class":104},[86,968,283],{"class":211},[86,970,971],{"class":88,"line":503},[86,972,973],{"class":725},"    // モックの戻り値を定義\n",[86,975,977,979,981,984,986],{"class":88,"line":976},26,[86,978,765],{"class":316},[86,980,320],{"class":104},[86,982,983],{"class":198},"mockResolvedValue",[86,985,212],{"class":211},[86,987,336],{"class":104},[86,989,991,994,996,998],{"class":88,"line":990},27,[86,992,993],{"class":211},"      data",[86,995,115],{"class":104},[86,997,924],{"class":316},[86,999,251],{"class":104},[86,1001,1003,1005],{"class":88,"line":1002},28,[86,1004,810],{"class":104},[86,1006,283],{"class":211},[86,1008,1010,1012,1014,1016,1018,1020,1022,1024],{"class":88,"line":1009},29,[86,1011,370],{"class":92},[86,1013,178],{"class":104},[86,1015,296],{"class":186},[86,1017,190],{"class":104},[86,1019,101],{"class":100},[86,1021,195],{"class":148},[86,1023,156],{"class":198},[86,1025,472],{"class":211},[86,1027,1029,1032,1034,1036,1039,1041,1044,1046,1048,1051,1053],{"class":88,"line":1028},30,[86,1030,1031],{"class":198},"    expect",[86,1033,212],{"class":211},[86,1035,632],{"class":198},[86,1037,1038],{"class":211},"())",[86,1040,320],{"class":104},[86,1042,1043],{"class":198},"toBe",[86,1045,212],{"class":211},[86,1047,248],{"class":240},[86,1049,1050],{"class":244},"TEST USER",[86,1052,248],{"class":240},[86,1054,283],{"class":211},[86,1056,1058,1060],{"class":88,"line":1057},31,[86,1059,280],{"class":104},[86,1061,283],{"class":211},[86,1063,1065,1067,1069,1071,1074,1076,1078,1080,1082,1084],{"class":88,"line":1064},32,[86,1066,898],{"class":198},[86,1068,212],{"class":211},[86,1070,248],{"class":240},[86,1072,1073],{"class":244},"異常系 ユーザーデータが取得できなかった場合",[86,1075,248],{"class":240},[86,1077,426],{"class":104},[86,1079,161],{"class":92},[86,1081,164],{"class":104},[86,1083,167],{"class":92},[86,1085,105],{"class":104},[86,1087,1089,1091,1093,1095,1097],{"class":88,"line":1088},33,[86,1090,765],{"class":316},[86,1092,320],{"class":104},[86,1094,983],{"class":198},[86,1096,212],{"class":211},[86,1098,336],{"class":104},[86,1100,1102,1104,1106,1108,1110,1113,1115],{"class":88,"line":1101},34,[86,1103,993],{"class":211},[86,1105,115],{"class":104},[86,1107,929],{"class":198},[86,1109,212],{"class":211},[86,1111,1112],{"class":329},"null",[86,1114,444],{"class":211},[86,1116,251],{"class":104},[86,1118,1120,1122],{"class":88,"line":1119},35,[86,1121,810],{"class":104},[86,1123,283],{"class":211},[86,1125,1127,1129,1131,1133,1135,1137,1139,1141],{"class":88,"line":1126},36,[86,1128,370],{"class":92},[86,1130,178],{"class":104},[86,1132,296],{"class":186},[86,1134,190],{"class":104},[86,1136,101],{"class":100},[86,1138,195],{"class":148},[86,1140,156],{"class":198},[86,1142,472],{"class":211},[86,1144,1146,1148,1150,1152,1154,1156,1158,1160,1163,1165,1167,1169,1171],{"class":88,"line":1145},37,[86,1147,1031],{"class":198},[86,1149,212],{"class":211},[86,1151,750],{"class":104},[86,1153,167],{"class":92},[86,1155,296],{"class":198},[86,1157,1038],{"class":211},[86,1159,320],{"class":104},[86,1161,1162],{"class":198},"toThrow",[86,1164,212],{"class":211},[86,1166,248],{"class":240},[86,1168,355],{"class":244},[86,1170,248],{"class":240},[86,1172,283],{"class":211},[86,1174,1176,1178],{"class":88,"line":1175},38,[86,1177,280],{"class":104},[86,1179,283],{"class":211},[86,1181,1183,1185],{"class":88,"line":1182},39,[86,1184,823],{"class":104},[86,1186,283],{"class":316},[15,1188,1189,1191,1192,1194],{},[18,1190,20],{}," を用いて ",[18,1193,34],{}," をモックしテストできました。",[10,1196,1197],{"id":1197},"テスタビリティを高めるアプローチ",[15,1199,1200,1201,1203,1204,1208],{},"Nuxt のインポート関数をモックする方法を解説しましたが、すこし踏み込んで、",[49,1202],{},"\nそもそもインポート関数をモックしなくても",[1205,1206,1207],"strong",{},"関数を切り出せばテストはもっとシンプルになります","。",[15,1210,1211],{},"テスタビリティを高めるために、先ほどのメソッドを高階関数として切り出してみます。",[76,1213,1215],{"className":78,"code":1214,"filename":80,"language":81,"meta":82,"style":82},"type User = {\n  familyName: string\n  firstName: string\n}\n\nexport const useUser = async () => {\n  const { data: user } = await useAsyncData\u003CUser>(async () => {\n    return {\n      firstName: 'kohei',\n      familyName: 'tsukiyama',\n    }\n  })\n\n  const toDisplayName = createDisplayNameFormatter(user.value)\n\n  return { user, toDisplayName }\n}\n\n// 高階関数として切り出す\nconst createDisplayNameFormatter = (user: User | null) => {\n  if (user === null) {\n    throw new Error('User is Missing')\n  }\n  const firstName = user.firstName\n  const familyName = user.familyName\n  const fullName = [firstName, familyName].filter(Boolean).join(' ')\n\n  const toDisplayName = () => {\n    return fullName.toUpperCase()\n  }\n\n  return toDisplayName\n}\n\n// テスト\nif (import.meta.vitest) {\n  const { describe, it, expect } = import.meta.vitest\n  describe('useUser', () => {\n    it('正常系 ユーザーデータが取得できる場合', () => {\n      const mockUser = {\n        firstName: 'test',\n        familyName: 'user',\n      }\n      // 関数を切り出したので useAsyncData の影響を受けない\n      const toDisplayName = createDisplayNameFormatter(mockUser)\n      expect(toDisplayName()).toBe('TEST USER')\n    })\n    it('異常系 ユーザーデータが取得できなかった場合', () => {\n      expect(() => createDisplayNameFormatter(null)).toThrow('User is Missing')\n    })\n  })\n}\n\n",[18,1216,1217,1227,1235,1243,1247,1251,1269,1305,1311,1325,1339,1343,1349,1353,1374,1378,1392,1396,1400,1405,1433,1450,1469,1473,1487,1501,1541,1545,1559,1571,1575,1579,1586,1590,1594,1599,1620,1652,1673,1694,1706,1722,1738,1744,1750,1768,1794,1801,1822,1856,1863,1870],{"__ignoreMap":82},[86,1218,1219,1221,1223,1225],{"class":88,"line":89},[86,1220,93],{"class":92},[86,1222,97],{"class":96},[86,1224,101],{"class":100},[86,1226,105],{"class":104},[86,1228,1229,1231,1233],{"class":88,"line":108},[86,1230,112],{"class":111},[86,1232,115],{"class":100},[86,1234,119],{"class":118},[86,1236,1237,1239,1241],{"class":88,"line":122},[86,1238,125],{"class":111},[86,1240,115],{"class":100},[86,1242,119],{"class":118},[86,1244,1245],{"class":88,"line":132},[86,1246,135],{"class":104},[86,1248,1249],{"class":88,"line":138},[86,1250,142],{"emptyLinePlaceholder":141},[86,1252,1253,1255,1257,1259,1261,1263,1265,1267],{"class":88,"line":145},[86,1254,149],{"class":148},[86,1256,152],{"class":92},[86,1258,156],{"class":155},[86,1260,101],{"class":100},[86,1262,161],{"class":92},[86,1264,164],{"class":104},[86,1266,167],{"class":92},[86,1268,105],{"class":104},[86,1270,1271,1273,1275,1277,1279,1281,1283,1285,1287,1289,1291,1293,1295,1297,1299,1301,1303],{"class":88,"line":172},[86,1272,175],{"class":92},[86,1274,178],{"class":104},[86,1276,181],{"class":111},[86,1278,115],{"class":104},[86,1280,187],{"class":186},[86,1282,190],{"class":104},[86,1284,101],{"class":100},[86,1286,195],{"class":148},[86,1288,199],{"class":198},[86,1290,202],{"class":104},[86,1292,205],{"class":96},[86,1294,208],{"class":104},[86,1296,212],{"class":211},[86,1298,215],{"class":92},[86,1300,164],{"class":104},[86,1302,167],{"class":92},[86,1304,105],{"class":104},[86,1306,1307,1309],{"class":88,"line":224},[86,1308,227],{"class":148},[86,1310,105],{"class":104},[86,1312,1313,1315,1317,1319,1321,1323],{"class":88,"line":232},[86,1314,235],{"class":211},[86,1316,115],{"class":104},[86,1318,241],{"class":240},[86,1320,245],{"class":244},[86,1322,248],{"class":240},[86,1324,251],{"class":104},[86,1326,1327,1329,1331,1333,1335,1337],{"class":88,"line":254},[86,1328,257],{"class":211},[86,1330,115],{"class":104},[86,1332,241],{"class":240},[86,1334,264],{"class":244},[86,1336,248],{"class":240},[86,1338,251],{"class":104},[86,1340,1341],{"class":88,"line":271},[86,1342,274],{"class":104},[86,1344,1345,1347],{"class":88,"line":277},[86,1346,280],{"class":104},[86,1348,283],{"class":211},[86,1350,1351],{"class":88,"line":286},[86,1352,142],{"emptyLinePlaceholder":141},[86,1354,1355,1357,1359,1361,1364,1366,1368,1370,1372],{"class":88,"line":291},[86,1356,175],{"class":92},[86,1358,296],{"class":186},[86,1360,101],{"class":100},[86,1362,1363],{"class":198}," createDisplayNameFormatter",[86,1365,212],{"class":211},[86,1367,317],{"class":316},[86,1369,320],{"class":104},[86,1371,323],{"class":316},[86,1373,283],{"class":211},[86,1375,1376],{"class":88,"line":307},[86,1377,142],{"emptyLinePlaceholder":141},[86,1379,1380,1382,1384,1386,1388,1390],{"class":88,"line":339},[86,1381,489],{"class":148},[86,1383,178],{"class":104},[86,1385,187],{"class":316},[86,1387,426],{"class":104},[86,1389,296],{"class":316},[86,1391,500],{"class":104},[86,1393,1394],{"class":88,"line":362},[86,1395,135],{"class":104},[86,1397,1398],{"class":88,"line":367},[86,1399,142],{"emptyLinePlaceholder":141},[86,1401,1402],{"class":88,"line":389},[86,1403,1404],{"class":725},"// 高階関数として切り出す\n",[86,1406,1407,1409,1411,1413,1415,1418,1420,1422,1425,1427,1429,1431],{"class":88,"line":410},[86,1408,549],{"class":92},[86,1410,1363],{"class":155},[86,1412,101],{"class":100},[86,1414,313],{"class":104},[86,1416,317],{"class":1417},"senS2",[86,1419,115],{"class":100},[86,1421,97],{"class":96},[86,1423,1424],{"class":100}," |",[86,1426,330],{"class":118},[86,1428,444],{"class":104},[86,1430,167],{"class":92},[86,1432,105],{"class":104},[86,1434,1435,1438,1440,1442,1444,1446,1448],{"class":88,"line":460},[86,1436,1437],{"class":148},"  if",[86,1439,313],{"class":211},[86,1441,317],{"class":316},[86,1443,326],{"class":100},[86,1445,330],{"class":329},[86,1447,333],{"class":211},[86,1449,336],{"class":104},[86,1451,1452,1455,1457,1459,1461,1463,1465,1467],{"class":88,"line":475},[86,1453,1454],{"class":148},"    throw",[86,1456,345],{"class":100},[86,1458,348],{"class":198},[86,1460,212],{"class":211},[86,1462,248],{"class":240},[86,1464,355],{"class":244},[86,1466,248],{"class":240},[86,1468,283],{"class":211},[86,1470,1471],{"class":88,"line":481},[86,1472,478],{"class":104},[86,1474,1475,1477,1479,1481,1483,1485],{"class":88,"line":486},[86,1476,175],{"class":92},[86,1478,373],{"class":186},[86,1480,101],{"class":100},[86,1482,187],{"class":316},[86,1484,320],{"class":104},[86,1486,386],{"class":316},[86,1488,1489,1491,1493,1495,1497,1499],{"class":88,"line":503},[86,1490,175],{"class":92},[86,1492,394],{"class":186},[86,1494,101],{"class":100},[86,1496,187],{"class":316},[86,1498,320],{"class":104},[86,1500,407],{"class":316},[86,1502,1503,1505,1507,1509,1511,1513,1515,1517,1519,1521,1523,1525,1527,1529,1531,1533,1535,1537,1539],{"class":88,"line":976},[86,1504,175],{"class":92},[86,1506,415],{"class":186},[86,1508,101],{"class":100},[86,1510,420],{"class":211},[86,1512,423],{"class":316},[86,1514,426],{"class":104},[86,1516,394],{"class":316},[86,1518,431],{"class":211},[86,1520,320],{"class":104},[86,1522,436],{"class":198},[86,1524,212],{"class":211},[86,1526,441],{"class":316},[86,1528,444],{"class":211},[86,1530,320],{"class":104},[86,1532,449],{"class":198},[86,1534,212],{"class":211},[86,1536,248],{"class":240},[86,1538,241],{"class":240},[86,1540,283],{"class":211},[86,1542,1543],{"class":88,"line":990},[86,1544,142],{"emptyLinePlaceholder":141},[86,1546,1547,1549,1551,1553,1555,1557],{"class":88,"line":1002},[86,1548,175],{"class":92},[86,1550,296],{"class":155},[86,1552,101],{"class":100},[86,1554,164],{"class":104},[86,1556,167],{"class":92},[86,1558,105],{"class":104},[86,1560,1561,1563,1565,1567,1569],{"class":88,"line":1009},[86,1562,227],{"class":148},[86,1564,415],{"class":316},[86,1566,320],{"class":104},[86,1568,469],{"class":198},[86,1570,472],{"class":211},[86,1572,1573],{"class":88,"line":1028},[86,1574,478],{"class":104},[86,1576,1577],{"class":88,"line":1057},[86,1578,142],{"emptyLinePlaceholder":141},[86,1580,1581,1583],{"class":88,"line":1064},[86,1582,489],{"class":148},[86,1584,1585],{"class":316}," toDisplayName\n",[86,1587,1588],{"class":88,"line":1088},[86,1589,135],{"class":104},[86,1591,1592],{"class":88,"line":1101},[86,1593,142],{"emptyLinePlaceholder":141},[86,1595,1596],{"class":88,"line":1119},[86,1597,1598],{"class":725},"// テスト\n",[86,1600,1601,1604,1606,1608,1610,1613,1615,1618],{"class":88,"line":1126},[86,1602,1603],{"class":148},"if",[86,1605,313],{"class":316},[86,1607,644],{"class":148},[86,1609,320],{"class":104},[86,1611,1612],{"class":186},"meta",[86,1614,320],{"class":104},[86,1616,1617],{"class":316},"vitest) ",[86,1619,336],{"class":104},[86,1621,1622,1624,1626,1628,1630,1632,1634,1636,1638,1640,1643,1645,1647,1649],{"class":88,"line":1145},[86,1623,175],{"class":92},[86,1625,178],{"class":104},[86,1627,681],{"class":186},[86,1629,426],{"class":104},[86,1631,671],{"class":186},[86,1633,426],{"class":104},[86,1635,676],{"class":186},[86,1637,190],{"class":104},[86,1639,101],{"class":100},[86,1641,1642],{"class":148}," import",[86,1644,320],{"class":104},[86,1646,1612],{"class":186},[86,1648,320],{"class":104},[86,1650,1651],{"class":316},"vitest\n",[86,1653,1654,1657,1659,1661,1663,1665,1667,1669,1671],{"class":88,"line":1175},[86,1655,1656],{"class":198},"  describe",[86,1658,212],{"class":211},[86,1660,248],{"class":240},[86,1662,883],{"class":244},[86,1664,248],{"class":240},[86,1666,426],{"class":104},[86,1668,164],{"class":104},[86,1670,167],{"class":92},[86,1672,105],{"class":104},[86,1674,1675,1678,1680,1682,1684,1686,1688,1690,1692],{"class":88,"line":1182},[86,1676,1677],{"class":198},"    it",[86,1679,212],{"class":211},[86,1681,248],{"class":240},[86,1683,905],{"class":244},[86,1685,248],{"class":240},[86,1687,426],{"class":104},[86,1689,164],{"class":104},[86,1691,167],{"class":92},[86,1693,105],{"class":104},[86,1695,1697,1700,1702,1704],{"class":88,"line":1696},40,[86,1698,1699],{"class":92},"      const",[86,1701,924],{"class":186},[86,1703,101],{"class":100},[86,1705,105],{"class":104},[86,1707,1709,1712,1714,1716,1718,1720],{"class":88,"line":1708},41,[86,1710,1711],{"class":211},"        firstName",[86,1713,115],{"class":104},[86,1715,241],{"class":240},[86,1717,944],{"class":244},[86,1719,248],{"class":240},[86,1721,251],{"class":104},[86,1723,1725,1728,1730,1732,1734,1736],{"class":88,"line":1724},42,[86,1726,1727],{"class":211},"        familyName",[86,1729,115],{"class":104},[86,1731,241],{"class":240},[86,1733,317],{"class":244},[86,1735,248],{"class":240},[86,1737,251],{"class":104},[86,1739,1741],{"class":88,"line":1740},43,[86,1742,1743],{"class":104},"      }\n",[86,1745,1747],{"class":88,"line":1746},44,[86,1748,1749],{"class":725},"      // 関数を切り出したので useAsyncData の影響を受けない\n",[86,1751,1753,1755,1757,1759,1761,1763,1766],{"class":88,"line":1752},45,[86,1754,1699],{"class":92},[86,1756,296],{"class":186},[86,1758,101],{"class":100},[86,1760,1363],{"class":198},[86,1762,212],{"class":211},[86,1764,1765],{"class":316},"mockUser",[86,1767,283],{"class":211},[86,1769,1771,1774,1776,1778,1780,1782,1784,1786,1788,1790,1792],{"class":88,"line":1770},46,[86,1772,1773],{"class":198},"      expect",[86,1775,212],{"class":211},[86,1777,632],{"class":198},[86,1779,1038],{"class":211},[86,1781,320],{"class":104},[86,1783,1043],{"class":198},[86,1785,212],{"class":211},[86,1787,248],{"class":240},[86,1789,1050],{"class":244},[86,1791,248],{"class":240},[86,1793,283],{"class":211},[86,1795,1797,1799],{"class":88,"line":1796},47,[86,1798,810],{"class":104},[86,1800,283],{"class":211},[86,1802,1804,1806,1808,1810,1812,1814,1816,1818,1820],{"class":88,"line":1803},48,[86,1805,1677],{"class":198},[86,1807,212],{"class":211},[86,1809,248],{"class":240},[86,1811,1073],{"class":244},[86,1813,248],{"class":240},[86,1815,426],{"class":104},[86,1817,164],{"class":104},[86,1819,167],{"class":92},[86,1821,105],{"class":104},[86,1823,1825,1827,1829,1831,1833,1835,1837,1839,1842,1844,1846,1848,1850,1852,1854],{"class":88,"line":1824},49,[86,1826,1773],{"class":198},[86,1828,212],{"class":211},[86,1830,750],{"class":104},[86,1832,167],{"class":92},[86,1834,1363],{"class":198},[86,1836,212],{"class":211},[86,1838,1112],{"class":329},[86,1840,1841],{"class":211},"))",[86,1843,320],{"class":104},[86,1845,1162],{"class":198},[86,1847,212],{"class":211},[86,1849,248],{"class":240},[86,1851,355],{"class":244},[86,1853,248],{"class":240},[86,1855,283],{"class":211},[86,1857,1859,1861],{"class":88,"line":1858},50,[86,1860,810],{"class":104},[86,1862,283],{"class":211},[86,1864,1866,1868],{"class":88,"line":1865},51,[86,1867,280],{"class":104},[86,1869,283],{"class":211},[86,1871,1873],{"class":88,"line":1872},52,[86,1874,135],{"class":104},[15,1876,1877,1878,1881,1882,1884],{},"関数を切り出し",[1205,1879,1880],{},"凝集度を低く","することにより ",[18,1883,34],{}," の影響を受けないようになり、モックを作成せずテストが書けるようになりました。",[10,1886,1887],{"id":1887},"まとめ",[1889,1890,1891,1900],"ul",{},[1892,1893,1894],"li",{},[1205,1895,1896,1897,1899],{},"Nuxt のインポート関数をモックするには ",[18,1898,20],{}," を使う",[1892,1901,1902],{},[1205,1903,1904],{},"関数を切り出すと凝集度が低くなりテスタビリティが高まる",[1906,1907,1908],"style",{},"html pre.shiki code .sGRfs, html code.shiki .sGRfs{--shiki-light:#9C3EDA;--shiki-default:#FF9492;--shiki-dark:#F97583}html pre.shiki code .sywW5, html code.shiki .sywW5{--shiki-light:#E2931D;--shiki-default:#FFB757;--shiki-dark:#B392F0}html pre.shiki code .sUBcA, html code.shiki .sUBcA{--shiki-light:#39ADB5;--shiki-default:#FF9492;--shiki-dark:#F97583}html pre.shiki code .seLpV, html code.shiki .seLpV{--shiki-light:#39ADB5;--shiki-default:#F0F3F6;--shiki-dark:#E1E4E8}html pre.shiki code .s-3tI, html code.shiki .s-3tI{--shiki-light:#E53935;--shiki-default:#FFB757;--shiki-dark:#FFAB70}html pre.shiki code .snYqn, html code.shiki .snYqn{--shiki-light:#E2931D;--shiki-default:#91CBFF;--shiki-dark:#79B8FF}html pre.shiki code .stP2V, html code.shiki .stP2V{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#FF9492;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .s8Xov, html code.shiki .s8Xov{--shiki-light:#90A4AE;--shiki-default:#DBB7FF;--shiki-dark:#B392F0}html pre.shiki code .sSuNx, html code.shiki .sSuNx{--shiki-light:#90A4AE;--shiki-default:#91CBFF;--shiki-dark:#79B8FF}html pre.shiki code .s7KVs, html code.shiki .s7KVs{--shiki-light:#6182B8;--shiki-default:#DBB7FF;--shiki-dark:#B392F0}html pre.shiki code .sLCpo, html code.shiki .sLCpo{--shiki-light:#E53935;--shiki-default:#F0F3F6;--shiki-dark:#E1E4E8}html pre.shiki code .sPUPB, html code.shiki .sPUPB{--shiki-light:#39ADB5;--shiki-default:#ADDCFF;--shiki-dark:#9ECBFF}html pre.shiki code .sSIes, html code.shiki .sSIes{--shiki-light:#91B859;--shiki-default:#ADDCFF;--shiki-dark:#9ECBFF}html pre.shiki code .sdyPO, html code.shiki .sdyPO{--shiki-light:#90A4AE;--shiki-default:#F0F3F6;--shiki-dark:#E1E4E8}html pre.shiki code .s4Pz2, html code.shiki .s4Pz2{--shiki-light:#39ADB5;--shiki-default:#91CBFF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .siCa7, html code.shiki .siCa7{--shiki-light:#E53935;--shiki-default:#72F088;--shiki-dark:#85E89D}html pre.shiki code .sOohs, html code.shiki .sOohs{--shiki-light:#9C3EDA;--shiki-default:#91CBFF;--shiki-dark:#B392F0}html pre.shiki code .sZPSj, html code.shiki .sZPSj{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#BDC4CC;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .senS2, html code.shiki .senS2{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#FFB757;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}",{"title":82,"searchDepth":122,"depth":122,"links":1910},[1911,1912,1913,1914],{"id":12,"depth":108,"text":13},{"id":60,"depth":108,"text":60},{"id":1197,"depth":108,"text":1197},{"id":1887,"depth":108,"text":1887},"2025-04-15T00:00:00.000Z","useAsyncData や useFetch のような Nuxt インポート関数をモックするのに便利な mockNuxtImport の紹介と凝集度を低くしテスタビリティを高める方法を紹介します。","md","/avatar_green_oab8qx.webp",{},"https://res.cloudinary.com/dyoyv8djx/image/upload/v1744641614/tsukiyama-blog/mock-nuxt-import/mock-nuxt-import-thumbnail_zqckp3.png","/tech/mock-nuxt-import",null,{"title":5,"description":1916},"tech/mock-nuxt-import",[1926,1927,1928],"Nuxt.js","Vue.js","Nuxt Test Utils","aFLjapuRouad5ud_SX80g5VT-5ZNkj4kNpvQcr4iuhc",{"title":82,"image":82,"description":82}]