【Vue】單元測試(Jest/Vue Test Utils)

在這里插入圖片描述

個人主頁:Guiat
歸屬專欄:Vue

在這里插入圖片描述

文章目錄

  • 1. Vue 單元測試簡介
    • 1.1 為什么需要單元測試
    • 1.2 測試工具介紹
  • 2. 環境搭建
    • 2.1 安裝依賴
    • 2.2 配置 Jest
  • 3. 編寫第一個測試
    • 3.1 組件示例
    • 3.2 編寫測試用例
    • 3.3 運行測試
  • 4. Vue Test Utils 核心 API
    • 4.1 掛載組件
    • 4.2 常用斷言和操作
  • 5. 測試組件交互
    • 5.1 測試用戶輸入
    • 5.2 測試 Props 和自定義事件
  • 6. 模擬依賴
    • 6.1 模擬 API 請求
    • 6.2 模擬 Vuex
  • 7. 測試 Vue Router
    • 7.1 模擬 Vue Router
    • 7.2 測試路由組件
  • 8. 快照測試
    • 8.1 基本快照測試
    • 8.2 更新快照
  • 9. 測試覆蓋率
    • 9.1 理解覆蓋率指標
    • 9.2 覆蓋率報告
  • 10. 測試最佳實踐
    • 10.1 組織測試
    • 10.2 測試原則
    • 10.3 常見測試場景對比
  • 11. 持續集成中的測試
    • 11.1 配置 CI 流程
    • 11.2 測試報告整合
  • 12. 測試驅動開發 (TDD) 與 Vue
    • 12.1 TDD 流程
    • 12.2 TDD 示例
  • 13. 常見問題與解決方案
    • 13.1 異步測試問題
    • 13.2 復雜 DOM 結構查找問題
    • 13.3 模擬復雜的 Vuex Store

正文

1. Vue 單元測試簡介

單元測試是確保代碼質量和可維護性的重要手段,在 Vue 應用開發中,Jest 和 Vue Test Utils 是最常用的測試工具組合。

1.1 為什么需要單元測試

  • 提早發現 bug,減少線上問題
  • 重構代碼時提供安全保障
  • 作為代碼的活文檔,幫助理解組件功能
  • 促進更好的代碼設計和模塊化

1.2 測試工具介紹

  • Jest: Facebook 開發的 JavaScript 測試框架,提供斷言庫、測試運行器和覆蓋率報告
  • Vue Test Utils: Vue.js 官方的單元測試實用工具庫,提供掛載組件和與之交互的方法

2. 環境搭建

2.1 安裝依賴

# 使用 Vue CLI 創建項目時選擇單元測試
vue create my-project# 或在現有項目中安裝
npm install --save-dev jest @vue/test-utils vue-jest babel-jest

2.2 配置 Jest

package.json 中添加 Jest 配置:

{"jest": {"moduleFileExtensions": ["js","vue"],"transform": {"^.+\\.vue$": "vue-jest","^.+\\.js$": "babel-jest"},"moduleNameMapper": {"^@/(.*)$": "<rootDir>/src/$1"},"testMatch": ["**/tests/unit/**/*.spec.[jt]s?(x)"],"collectCoverage": true,"collectCoverageFrom": ["src/**/*.{js,vue}","!src/main.js","!src/router/index.js","!**/node_modules/**"]}
}

3. 編寫第一個測試

3.1 組件示例

假設有一個簡單的計數器組件 Counter.vue

<template><div><span class="count">{{ count }}</span><button @click="increment">增加</button><button @click="decrement">減少</button></div>
</template><script>
export default {data() {return {count: 0}},methods: {increment() {this.count += 1},decrement() {this.count -= 1}}
}
</script>

3.2 編寫測試用例

創建 tests/unit/Counter.spec.js 文件:

import { mount } from '@vue/test-utils'
import Counter from '@/components/Counter.vue'describe('Counter.vue', () => {it('初始計數為0', () => {const wrapper = mount(Counter)expect(wrapper.find('.count').text()).toBe('0')})it('點擊增加按鈕后計數加1', async () => {const wrapper = mount(Counter)await wrapper.findAll('button').at(0).trigger('click')expect(wrapper.find('.count').text()).toBe('1')})it('點擊減少按鈕后計數減1', async () => {const wrapper = mount(Counter)await wrapper.findAll('button').at(1).trigger('click')expect(wrapper.find('.count').text()).toBe('-1')})
})

3.3 運行測試

npm run test:unit

4. Vue Test Utils 核心 API

4.1 掛載組件

// 完全掛載組件及其子組件
const wrapper = mount(Component, {propsData: { /* 組件 props */ },data() { /* 覆蓋組件數據 */ },mocks: { /* 模擬全局對象 */ },stubs: { /* 替換子組件 */ }
})// 只掛載當前組件,不渲染子組件
const wrapper = shallowMount(Component, options)

4.2 常用斷言和操作

// 查找元素
wrapper.find('div') // CSS 選擇器
wrapper.find('.class-name')
wrapper.find('[data-test="id"]')
wrapper.findComponent(ChildComponent)// 檢查內容和屬性
expect(wrapper.text()).toContain('Hello')
expect(wrapper.html()).toContain('<div>')
expect(wrapper.attributes('id')).toBe('my-id')
expect(wrapper.classes()).toContain('active')// 觸發事件
await wrapper.find('button').trigger('click')
await wrapper.find('input').setValue('new value')// 訪問組件實例
console.log(wrapper.vm.count) // 訪問數據
wrapper.vm.increment() // 調用方法// 更新組件
await wrapper.setProps({ color: 'red' })
await wrapper.setData({ count: 5 })

5. 測試組件交互

5.1 測試用戶輸入

假設有一個表單組件 Form.vue

<template><form @submit.prevent="submitForm"><input v-model="username" data-test="username" /><input type="password" v-model="password" data-test="password" /><button type="submit" data-test="submit">登錄</button><p v-if="error" data-test="error">{{ error }}</p></form>
</template><script>
export default {data() {return {username: '',password: '',error: ''}},methods: {submitForm() {if (!this.username || !this.password) {this.error = '用戶名和密碼不能為空'return}this.$emit('form-submitted', {username: this.username,password: this.password})this.error = ''}}
}
</script>

測試代碼 Form.spec.js

import { mount } from '@vue/test-utils'
import Form from '@/components/Form.vue'describe('Form.vue', () => {it('提交空表單時顯示錯誤信息', async () => {const wrapper = mount(Form)await wrapper.find('[data-test="submit"]').trigger('click')expect(wrapper.find('[data-test="error"]').text()).toBe('用戶名和密碼不能為空')})it('表單正確提交時觸發事件', async () => {const wrapper = mount(Form)await wrapper.find('[data-test="username"]').setValue('user1')await wrapper.find('[data-test="password"]').setValue('pass123')await wrapper.find('form').trigger('submit')expect(wrapper.emitted('form-submitted')).toBeTruthy()expect(wrapper.emitted('form-submitted')[0][0]).toEqual({username: 'user1',password: 'pass123'})})
})

5.2 測試 Props 和自定義事件

假設有一個展示商品的組件 ProductItem.vue

<template><div class="product-item"><h3>{{ product.name }}</h3><p>{{ product.price }}元</p><button @click="addToCart">加入購物車</button></div>
</template><script>
export default {props: {product: {type: Object,required: true}},methods: {addToCart() {this.$emit('add-to-cart', this.product.id)}}
}
</script>

測試代碼 ProductItem.spec.js

import { mount } from '@vue/test-utils'
import ProductItem from '@/components/ProductItem.vue'describe('ProductItem.vue', () => {const product = {id: 1,name: '測試商品',price: 99}it('正確渲染商品信息', () => {const wrapper = mount(ProductItem, {propsData: { product }})expect(wrapper.find('h3').text()).toBe('測試商品')expect(wrapper.find('p').text()).toBe('99元')})it('點擊按鈕觸發加入購物車事件', async () => {const wrapper = mount(ProductItem, {propsData: { product }})await wrapper.find('button').trigger('click')expect(wrapper.emitted('add-to-cart')).toBeTruthy()expect(wrapper.emitted('add-to-cart')[0]).toEqual([1])})
})

6. 模擬依賴

6.1 模擬 API 請求

假設有一個使用 axios 獲取用戶數據的組件 UserList.vue

<template><div><div v-if="loading">加載中...</div><ul v-else><li v-for="user in users" :key="user.id" data-test="user">{{ user.name }}</li></ul><div v-if="error" data-test="error">{{ error }}</div></div>
</template><script>
import axios from 'axios'export default {data() {return {users: [],loading: true,error: null}},created() {this.fetchUsers()},methods: {async fetchUsers() {try {this.loading = trueconst response = await axios.get('/api/users')this.users = response.data} catch (error) {this.error = '獲取用戶列表失敗'} finally {this.loading = false}}}
}
</script>

測試代碼 UserList.spec.js

import { mount, flushPromises } from '@vue/test-utils'
import UserList from '@/components/UserList.vue'
import axios from 'axios'// 模擬 axios
jest.mock('axios')describe('UserList.vue', () => {it('成功獲取用戶列表', async () => {// 設置 axios.get 的模擬返回值axios.get.mockResolvedValue({data: [{ id: 1, name: '用戶1' },{ id: 2, name: '用戶2' }]})const wrapper = mount(UserList)// 等待異步操作完成await flushPromises()// 斷言加載狀態消失expect(wrapper.find('div').text()).not.toBe('加載中...')// 斷言用戶列表已渲染const users = wrapper.findAll('[data-test="user"]')expect(users).toHaveLength(2)expect(users.at(0).text()).toBe('用戶1')expect(users.at(1).text()).toBe('用戶2')})it('獲取用戶列表失敗', async () => {// 設置 axios.get 模擬拋出錯誤axios.get.mockRejectedValue(new Error('API 錯誤'))const wrapper = mount(UserList)// 等待異步操作完成await flushPromises()// 斷言顯示錯誤信息expect(wrapper.find('[data-test="error"]').text()).toBe('獲取用戶列表失敗')})
})

6.2 模擬 Vuex

假設有一個使用 Vuex 的計數器組件 VuexCounter.vue

<template><div><span data-test="count">{{ count }}</span><button @click="increment">增加</button><button @click="decrement">減少</button></div>
</template><script>
import { mapState, mapActions } from 'vuex'export default {computed: {...mapState(['count'])},methods: {...mapActions(['increment', 'decrement'])}
}
</script>

測試代碼 VuexCounter.spec.js

import { mount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import VuexCounter from '@/components/VuexCounter.vue'// 創建擴展的 Vue 實例
const localVue = createLocalVue()
localVue.use(Vuex)describe('VuexCounter.vue', () => {let storelet actionslet statebeforeEach(() => {// 設置模擬的 state 和 actionsstate = {count: 5}actions = {increment: jest.fn(),decrement: jest.fn()}// 創建模擬的 storestore = new Vuex.Store({state,actions})})it('從 store 渲染計數', () => {const wrapper = mount(VuexCounter, {store,localVue})expect(wrapper.find('[data-test="count"]').text()).toBe('5')})it('調度 increment action', async () => {const wrapper = mount(VuexCounter, {store,localVue})await wrapper.findAll('button').at(0).trigger('click')expect(actions.increment).toHaveBeenCalled()})it('調度 decrement action', async () => {const wrapper = mount(VuexCounter, {store,localVue})await wrapper.findAll('button').at(1).trigger('click')expect(actions.decrement).toHaveBeenCalled()})
})

7. 測試 Vue Router

7.1 模擬 Vue Router

使用 Vue Router 的導航組件 Navigation.vue

<template><nav><router-link to="/" data-test="home">首頁</router-link><router-link to="/about" data-test="about">關于</router-link><button @click="goToContact" data-test="contact">聯系我們</button></nav>
</template><script>
export default {methods: {goToContact() {this.$router.push('/contact')}}
}
</script>

測試代碼 Navigation.spec.js

import { mount, createLocalVue } from '@vue/test-utils'
import VueRouter from 'vue-router'
import Navigation from '@/components/Navigation.vue'const localVue = createLocalVue()
localVue.use(VueRouter)describe('Navigation.vue', () => {it('點擊按鈕進行路由導航', async () => {const router = new VueRouter()// 監視 router.push 方法router.push = jest.fn()const wrapper = mount(Navigation, {localVue,router})await wrapper.find('[data-test="contact"]').trigger('click')expect(router.push).toHaveBeenCalledWith('/contact')})
})

7.2 測試路由組件

假設有一個根據路由參數顯示內容的組件 UserDetails.vue

<template><div><h1 data-test="user-name">{{ userName }}</h1></div>
</template><script>
export default {data() {return {userName: ''}},created() {// 根據路由參數獲取用戶名this.userName = `用戶 ${this.$route.params.id}`}
}
</script>

測試代碼 UserDetails.spec.js

import { mount, createLocalVue } from '@vue/test-utils'
import VueRouter from 'vue-router'
import UserDetails from '@/components/UserDetails.vue'const localVue = createLocalVue()
localVue.use(VueRouter)describe('UserDetails.vue', () => {it('根據路由參數顯示用戶名', () => {// 創建帶有初始路由和參數的路由實例const router = new VueRouter()// 創建帶有模擬路由的組件const wrapper = mount(UserDetails, {localVue,mocks: {$route: {params: {id: '42'}}}})expect(wrapper.find('[data-test="user-name"]').text()).toBe('用戶 42')})
})

8. 快照測試

快照測試可以確保組件 UI 不會意外改變。

8.1 基本快照測試

import { mount } from '@vue/test-utils'
import MessageDisplay from '@/components/MessageDisplay.vue'describe('MessageDisplay.vue', () => {it('渲染的 UI 與上次快照匹配', () => {const wrapper = mount(MessageDisplay, {propsData: {message: '歡迎使用 Vue!'}})expect(wrapper.html()).toMatchSnapshot()})
})

8.2 更新快照

當組件合法變更后,需要更新快照:

# 更新所有快照
jest --updateSnapshot# 更新特定測試的快照
jest --updateSnapshot -t 'MessageDisplay'

9. 測試覆蓋率

9.1 理解覆蓋率指標

Jest 提供四種覆蓋率指標:

  • 語句覆蓋率(Statements): 程序中執行到的語句比例
  • 分支覆蓋率(Branches): 程序中執行到的分支比例(if/else)
  • 函數覆蓋率(Functions): 被調用過的函數比例
  • 行覆蓋率(Lines): 程序中執行到的行數比例

9.2 覆蓋率報告

執行帶覆蓋率報告的測試:

jest --coverage

典型的覆蓋率報告輸出:

-----------------------|---------|----------|---------|---------|-------------------
File                   | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------------------|---------|----------|---------|---------|-------------------
All files              |   85.71 |    83.33 |   85.71 |   85.71 |                   components/Counter.vue|  100.00 |   100.00 |  100.00 |  100.00 |                   components/Form.vue   |   71.42 |    66.67 |   71.42 |   71.42 | 15-18             
-----------------------|---------|----------|---------|---------|-------------------

10. 測試最佳實踐

10.1 組織測試

  • 按照組件結構組織測試文件
  • 為每個組件創建單獨的測試文件
  • 使用清晰的測試描述和分組
describe('組件名', () => {describe('功能1', () => {it('子功能 A', () => { /* ... */ })it('子功能 B', () => { /* ... */ })})describe('功能2', () => {it('子功能 C', () => { /* ... */ })it('子功能 D', () => { /* ... */ })})
})

10.2 測試原則

  • 測試行為而非實現: 關注組件的輸出而非內部工作方式
  • 使用數據屬性標記測試元素: 使用 data-test 屬性標記用于測試的元素
  • 一個測試只測一個行為: 每個測試只斷言一個行為
  • 避免過度模擬: 盡量減少模擬的數量
  • 編寫可維護的測試: 測試代碼應該和產品代碼一樣重視質量

10.3 常見測試場景對比

graph TDA[測試場景] --> B[組件渲染]A --> C[用戶交互]A --> D[API 調用]A --> E[Vuex 整合]A --> F[路由功能]B --> B1[使用 mount() 測試完整渲染]B --> B2[使用 shallowMount() 測試隔離組件]B --> B3[使用 toMatchSnapshot() 測試 UI 穩定性]C --> C1[使用 trigger() 測試點擊事件]C --> C2[使用 setValue() 測試表單輸入]C --> C3[使用 emitted() 測試自定義事件]D --> D1[使用 jest.mock() 模擬 axios]D --> D2[測試加載狀態]D --> D3[測試成功/失敗處理]E --> E1[模擬 Vuex store]E --> E2[測試 getter 計算屬性]E --> E3[驗證 actions 被正確調度]F --> F1[使用 mocks 模擬 $route]F --> F2[驗證 router.push 調用]F --> F3[測試基于路由的組件行為]

11. 持續集成中的測試

11.1 配置 CI 流程

在 GitHub Actions 中設置 Vue 測試的 .github/workflows/test.yml 配置:

name: Unit Testson:push:branches: [ main ]pull_request:branches: [ main ]jobs:test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v2- name: Use Node.jsuses: actions/setup-node@v2with:node-version: '14'- name: Install dependenciesrun: npm ci- name: Run testsrun: npm run test:unit- name: Upload coverageuses: codecov/codecov-action@v1with:token: ${{ secrets.CODECOV_TOKEN }}

11.2 測試報告整合

將 Jest 測試報告整合到 CI 系統,使用 JUnit 格式:

// package.json
{"jest": {"reporters": ["default",["jest-junit", {"outputDirectory": "./test-results/jest","outputName": "results.xml"}]]}
}

12. 測試驅動開發 (TDD) 與 Vue

12.1 TDD 流程

  1. 編寫失敗的測試: 先編寫測試,驗證未實現的功能
  2. 編寫最少的代碼使測試通過: 實現功能使測試通過
  3. 重構代碼: 優化實現,保持測試通過

12.2 TDD 示例

假設我們要開發一個待辦事項組件,先編寫測試:

// TodoList.spec.js
import { mount } from '@vue/test-utils'
import TodoList from '@/components/TodoList.vue'describe('TodoList.vue', () => {it('顯示待辦事項列表', () => {const wrapper = mount(TodoList, {propsData: {todos: [{ id: 1, text: '學習 Vue', done: false },{ id: 2, text: '學習單元測試', done: true }]}})const items = wrapper.findAll('[data-test="todo-item"]')expect(items).toHaveLength(2)expect(items.at(0).text()).toContain('學習 Vue')expect(items.at(1).text()).toContain('學習單元測試')expect(items.at(1).classes()).toContain('completed')})it('添加新的待辦事項', async () => {const wrapper = mount(TodoList)await wrapper.find('[data-test="new-todo"]').setValue('新任務')await wrapper.find('form').trigger('submit')expect(wrapper.findAll('[data-test="todo-item"]')).toHaveLength(1)expect(wrapper.find('[data-test="todo-item"]').text()).toContain('新任務')})
})

然后實現組件:

<template><div><form @submit.prevent="addTodo"><input v-model="newTodo" data-test="new-todo" /><button type="submit">添加</button></form><ul><li v-for="todo in allTodos" :key="todo.id" :class="{ completed: todo.done }"data-test="todo-item">{{ todo.text }}</li></ul></div>
</template><script>
export default {props: {todos: {type: Array,default: () => []}},data() {return {newTodo: '',localTodos: []}},computed: {allTodos() {return [...this.todos, ...this.localTodos]}},methods: {addTodo() {if (this.newTodo.trim()) {this.localTodos.push({id: Date.now(),text: this.newTodo,done: false})this.newTodo = ''}}}
}
</script><style scoped>
.completed {text-decoration: line-through;
}
</style>

13. 常見問題與解決方案

13.1 異步測試問題

問題: 測試未等待組件更新就進行斷言
解決方案: 使用 awaitnextTick

// 錯誤示例
wrapper.find('button').trigger('click')
expect(wrapper.text()).toContain('已更新')  // 可能失敗// 正確示例
await wrapper.find('button').trigger('click')
expect(wrapper.text()).toContain('已更新')  // 已等待更新

13.2 復雜 DOM 結構查找問題

問題: 難以準確定位要測試的元素
解決方案: 使用 data-test 屬性標記測試元素

<template><div><h1 data-test="title">標題</h1><p data-test="content">內容</p></div>
</template>
// 使用 data-test 屬性查找元素
wrapper.find('[data-test="title"]')

13.3 模擬復雜的 Vuex Store

問題: 大型應用中 Store 結構復雜
解決方案: 只模擬測試需要的部分

const store = new Vuex.Store({modules: {user: {namespaced: true,state: { name: 'Test User' },getters: {fullName: () => 'Test User Full'},actions: {login: jest.fn()}},// 其他模塊可以省略}
})

結語
感謝您的閱讀!期待您的一鍵三連!歡迎指正!

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80704.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80704.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80704.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據湖的管理系統管什么?主流產品有哪些?

一、數據湖的管理系統管什么&#xff1f; 數據湖的管理系統主要負責管理和優化存儲在數據湖中的大量異構數據&#xff0c;確保這些數據能夠被有效地存儲、處理、訪問和治理。以下是數據湖管理系統的主要職責&#xff1a; 數據攝入管理&#xff1a;管理系統需要支持從多種來源&…

英文中日期讀法

英文日期的讀法和寫法因地區&#xff08;英式英語與美式英語&#xff09;和正式程度有所不同&#xff0c;以下是詳細說明&#xff1a; 一、日期格式 英式英語 (日-月-年) 寫法&#xff1a;1(st) January 2023 或 1/1/2023讀法&#xff1a;"the first of January, twenty t…

衡量矩陣數值穩定性的關鍵指標:矩陣的條件數

文章目錄 1. 定義2. 為什么要定義條件數&#xff1f;2.1 分析線性系統 A ( x Δ x ) b Δ b A(x \Delta x) b \Delta b A(xΔx)bΔb2.2 分析線性系統 ( A Δ A ) ( x Δ x ) b (A \Delta A)(x \Delta x) b (AΔA)(xΔx)b2.3 定義矩陣的條件數 3. 性質及幾何意義3…

4月22日復盤-開始卷積神經網絡

4月24日復盤 一、CNN 視覺處理三大任務&#xff1a;圖像分類、目標檢測、圖像分割 上游&#xff1a;提取特征&#xff0c;CNN 下游&#xff1a;分類、目標、分割等&#xff0c;具體的業務 1. 概述 ? 卷積神經網絡是深度學習在計算機視覺領域的突破性成果。在計算機視覺領…

【網絡原理】從零開始深入理解TCP的各項特性和機制.(三)

上篇介紹了網絡原理傳輸層TCP協議的知識,本篇博客給大家帶來的是網絡原理剩余的內容, 總體來說,這部分內容沒有上兩篇文章那么重要,本篇知識有一個印象即可. &#x1f40e;文章專欄: JavaEE初階 &#x1f680;若有問題 評論區見 ? 歡迎大家點贊 評論 收藏 分享 如果你不知道分…

解決qnn htp 后端不支持boolean 數據類型的方法。

一、背景 1.1 問題原因 Qnn 模型在使用fp16的模型轉換不支持類型是boolean的cast 算子&#xff0c;因為 htp 后端支持量化數據類型或者fp16&#xff0c;不支持boolean 類型。 ${QNN_SDK_ROOT_27}/bin/x86_64-linux-clang/qnn-model-lib-generator -c ./bge_small_fp16.cpp -b …

使用Three.js搭建自己的3Dweb模型(從0到1無廢話版本)

教學視頻參考&#xff1a;B站——Three.js教學 教學鏈接&#xff1a;Three.js中文網 老陳打碼 | 麒躍科技 一.什么是Three.js&#xff1f; Three.js? 是一個基于 JavaScript 的 ?3D 圖形庫&#xff0c;用于在網頁瀏覽器中創建和渲染交互式 3D 內容。它基于 WebGL&#xff0…

PostgreSQL WAL 冪等性詳解

1. WAL簡介 WAL&#xff08;Write-Ahead Logging&#xff09;是PostgreSQL的核心機制之一。其基本理念是&#xff1a;在修改數據庫數據頁之前&#xff0c;必須先將這次修改操作寫入到WAL日志中。 這確保了即使發生崩潰&#xff0c;數據庫也可以根據WAL日志進行恢復。 恢復的核…

git提交規范記錄,常見的提交類型及模板、示例

Git提交規范是一種約定俗成的提交信息編寫標準&#xff0c;旨在使代碼倉庫的提交歷史更加清晰、可讀和有組織。以下是常見的Git提交類型及其對應的提交模板&#xff1a; 提交信息的基本結構 一個標準的Git提交信息通常包含以下三個主要部分&#xff1a; Header?&#xff1a;描…

FastAPI系列06:FastAPI響應(Response)

FastAPI響應&#xff08;Response&#xff09; 1、Response入門2、Response基本操作設置響應體&#xff08;返回數據&#xff09;設置狀態碼設置響應頭設置 Cookies 3、響應模型 response_model4、響應類型 response_classResponse派生類自定義response_class 在“FastAPI系列0…

每日一題(小白)模擬娛樂篇33

首先&#xff0c;理解題意是十分重要的&#xff0c;我們是要求最短路徑&#xff0c;這道題可以用dfs&#xff0c;但是題目給出的數據是有規律的&#xff0c;我們可以嘗試模擬的過程使用簡單的方法做出來。每隔w數字就會向下轉向&#xff0c;就比如題目上示例的w6&#xff0c;無…

哈希封裝unordered_map和unordered_set的模擬實現

文章目錄 &#xff08;一&#xff09;認識unordered_map和unordered_set&#xff08;二&#xff09;模擬實現unordered_map和unordered_set2.1 實現出復用哈希表的框架2.2 迭代器iterator的實現思路分析2.3 unordered_map支持[] &#xff08;三&#xff09;結束語 &#xff08;…

Java學習-Java基礎

1.重寫與重載的區別 重寫發生在父子類之間,重載發生在同類之間構造方法不能重寫,只能重載重寫的方法返回值,參數列表,方法名必須相同重載的方法名相同,參數列表必須不同重寫的方法的訪問權限不能比父類方法的訪問權限更低 2.接口和抽象類的區別 接口是interface,抽象類是abs…

BG開發者日志0427:故事的起點

1、4月26日晚上&#xff0c;BG項目的gameplay部分開發完畢&#xff0c;后續是細節以及試玩版優化。 開發重心轉移到story部分&#xff0c;目前剛開始&#xff0c; 確切地說以前是長期擱置狀態&#xff0c;因為過去的四個月中gameplay部分優先開發。 --- 2、BG這個項目的起點…

頭歌實訓之游標觸發器

&#x1f31f; 各位看官好&#xff0c;我是maomi_9526&#xff01; &#x1f30d; 種一棵樹最好是十年前&#xff0c;其次是現在&#xff01; &#x1f680; 今天來學習C語言的相關知識。 &#x1f44d; 如果覺得這篇文章有幫助&#xff0c;歡迎您一鍵三連&#xff0c;分享給更…

【深度學習】多頭注意力機制的實現|pytorch

博主簡介&#xff1a;努力學習的22級計算機科學與技術本科生一枚&#x1f338;博主主頁&#xff1a; Yaoyao2024往期回顧&#xff1a;【深度學習】注意力機制| 基于“上下文”進行編碼,用更聰明的矩陣乘法替代笨重的全連接每日一言&#x1f33c;: 路漫漫其修遠兮&#xff0c;吾…

java16

1.API續集 可以導入別人寫好的clone的jar包 注意&#xff1a;方法要有調用者&#xff0c;如果調用者是null就會報錯 2.如何導入別人寫好的jar包 復制jar包然后粘貼在lib里面&#xff0c;然后右鍵點擊jar包再點擊下面的add 3.關于打印java中的引用數據類型

PostgreSQL的擴展 credcheck

PostgreSQL的擴展 credcheck credcheck 是 PostgreSQL 的一個安全擴展&#xff0c;專門用于強制實施密碼策略和憑證檢查&#xff0c;特別適合需要符合安全合規要求的數據庫環境。 一、擴展概述 1. 主要功能 強制密碼復雜度要求防止使用常見弱密碼密碼過期策略實施密碼重復使…

MyBatis中的@Param注解-如何傳入多個不同類型的參數

mybatis中參數識別規則 默認情況下,MyBatis 會按照參數位置自動分配名稱:param1, param2, param3, ...或者 arg0, arg1。 // Mapper 接口方法 User getUserByIdAndName(Integer id, String name); 以上接口在XML中只能通過param1或者arg0這樣的方式來引用,可讀性差。 &l…

DIFY教程第一集:安裝Dify配置環境

一、Dify的介紹 https://dify.ai/ Dify 是一款創新的智能生活助手應用&#xff0c;旨在為您提供便捷、高效的服務。通過人工智能技術&#xff0c; Dify 可以實現語音 助手、智能家居控制、日程管理等功能&#xff0c;助您輕松應對生活瑣事&#xff0c;享受智慧生活。簡約的…