UnitTesting 单元测试

news2024/9/20 6:02:06

1. 测试分为两种及详细介绍测试书籍:

  1.1 Unit Test : 单元测试

  - test the business logic in your app : 测试应用中的业务逻辑

  1.2 UI  Test :  界面测试

  - test the UI of your app : 测试应用中的界面

  1.3 测试书籍网址:《Testing Swift》 icon-default.png?t=N7T8https://www.hackingwithswift.com/store/testing-swift

2. ViewModel 单元测试

  2.1 创建 ViewModel,UnitTestingBootcampViewModel.swift

import Foundation
import SwiftUI
import Combine

/// 单元测试 ViewModel
class UnitTestingBootcampViewModel: ObservableObject{
    @Published var isPremium: Bool
    @Published var dataArray: [String] = []
    @Published var selectedItem: String? = nil
    let dataService: NewDataServiceProtocol
    var cancellable = Set<AnyCancellable>()
    
    init(isPremium: Bool, dataService: NewDataServiceProtocol = NewMockDataService(items: nil)) {
        self.isPremium = isPremium
        self.dataService = dataService
    }
    
    /// 添加子项
    func addItem(item: String){
        // 为空不往下执行
        guard !item.isEmpty else { return }
        self.dataArray.append(item)
    }
    
    /// 选中项
    func selectItem(item: String){
        if let x = dataArray.first(where: {$0 == item}){
            selectedItem = x
        }else{
            selectedItem = nil
        }
    }
    
    /// 保存项
    func saveItem(item: String) throws{
        guard !item.isEmpty else{
            throw DataError.noData
        }
        
        if let x = dataArray.first(where: {$0 == item}){
            print("Save item here!!! \(x)")
        } else {
            throw DataError.itemNotFound
        }
    }
    
    /// 错误信息
    enum DataError: LocalizedError{
        case noData
        case itemNotFound
    }
    
    /// 请求返回数据
    func downloadWithEscaping() {
        dataService.downloadItemsWithEscaping { [weak self] returnedItems in
            self?.dataArray = returnedItems
        }
    }
    
    /// 下载用到的组合
    func downloadWithCombine() {
        dataService.downloadItemsWithCombine()
            .sink { _ in
                
            } receiveValue: { [weak self] returnedItems in
                self?.dataArray = returnedItems
            }
            .store(in: &cancellable)
    }
}

  2.2 创建测试文件

    当创建项目时,没有选择 Include Tests/包含测试 选项时,需要添加文件去对应项目,不然测试文件会报 No such module 'XCTest' 编译错误

    添加单元测试文件:

    方法一 : 选择项目 -> 菜单栏 Editor -> Add Target... -> 弹出对话框,选择 Test 栏下 -> Unit Testing Bundle -> 填写信息/可默认 -> Finish,完成创建单元测试文件。

    方法二 : 选择项目,点击 PROJECT 列,最下的 + 按钮,弹出对话框,选择 Test 栏下 ,后面步骤与上一致

    创建单元测试文件 UnitTestingBootcampViewModel_Tests.swift

import XCTest
import Combine
/// 导入项目
@testable import SwiftfulThinkingAdvancedLearning

// 《Testing Swift》 测试书籍
// 书籍网址: https://www.hackingwithswift.com/store/testing-swift
// Naming Structure: test_UnitOfWork_StateUnderTest_ExpectedBehavior -  结构体命名: 测试_工作单元_测试状态_预期的行为
// Naming Structure: test_[struct or class]_[variable or function]_[expected result] - 测试_[结构体 或者 类的名称]_[类中的变量名 或者 函数名称]_[预期结果 预期值]
// Testing Structure: Given, When, Then - 测试结构: 给定,什么时候,然后

final class UnitTestingBootcampViewModel_Tests: XCTestCase {
    /// 解决多次引用相同的类
    var viewModel: UnitTestingBootcampViewModel?
    var cancellables = Set<AnyCancellable>()
    
    /// 开始设置数据
    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.
        viewModel = UnitTestingBootcampViewModel(isPremium: Bool.random())
    }
    
    /// 结束重置数据
    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        viewModel = nil
        cancellables.removeAll()
    }
    
    /// 单元测试函数名,根据命名规则命名:测试_类名称_是否高质量_应该为真
    func test_UnitTestingBootcampViewModel_isPremium_shouldBeTrue(){
        // Given
        let userIsPremium: Bool = true
        
        // When
        let vm = UnitTestingBootcampViewModel(isPremium: userIsPremium)
        
        // Then
        XCTAssertTrue(vm.isPremium)
    }
    
    /// 单元测试函数名 根据命名规则命名:测试_类名称_是否高质量_应该为假
    func test_UnitTestingBootcampViewModel_isPremium_shouldBeFalse(){
        // Given
        let userIsPremium: Bool = false
        
        // When
        let vm = UnitTestingBootcampViewModel(isPremium: userIsPremium)
        
        // Then
        XCTAssertFalse(vm.isPremium)
    }
    
    /// 单元测试函数名 根据命名规则命名:测试_类名称_是否高品质_注入值
    func test_UnitTestingBootcampViewModel_isPremium_shouldBeInjectedValue(){
        // Given
        let userIsPremium: Bool = Bool.random()
        
        // When
        let vm = UnitTestingBootcampViewModel(isPremium: userIsPremium)
        
        // Then
        XCTAssertEqual(vm.isPremium, userIsPremium)
    }
    
    /// 单元测试函数名 根据命名规则命名 - 注入值_压力 / for 循环
    func test_UnitTestingBootcampViewModel_isPremium_shouldBeInjectedValue_stress(){
        for _ in 0 ..< 10 {
            // Given
            let userIsPremium: Bool = Bool.random()
            // When
            let vm = UnitTestingBootcampViewModel(isPremium: userIsPremium)
            // Then
            XCTAssertEqual(vm.isPremium, userIsPremium)
        }
    }
    
    /// 单元测试函数名 根据命名规则命名 - 数组_预期值:为空
    func test_UnitTestingBootcampViewModel_dataArray_shouldBeEmpty(){
        // Given
        
        // When
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // Then 断言 = 判定
        XCTAssertTrue(vm.dataArray.isEmpty)
        XCTAssertEqual(vm.dataArray.count, 0)
    }
    
    /// 单元测试函数名 根据命名规则命名 - 数组_预期值:添加项
    func test_UnitTestingBootcampViewModel_dataArray_shouldAddItems(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let loopCount: Int = Int.random(in: 1..<100)
        
        for _ in 0 ..< loopCount{
            vm.addItem(item: UUID().uuidString)
        }
        
        // Then 断言 = 判定
        XCTAssertTrue(!vm.dataArray.isEmpty)
        XCTAssertFalse(vm.dataArray.isEmpty)
        XCTAssertEqual(vm.dataArray.count, loopCount)
        XCTAssertNotEqual(vm.dataArray.count, 0)
        // GreaterThan 大于
        XCTAssertGreaterThan(vm.dataArray.count, 0)
        // XCTAssertGreaterThanOrEqual
        // XCTAssertLessThan
        // XCTAssertLessThanOrEqual
    }
    
    /// 单元测试函数名 根据命名规则命名 - 数组_预期值:添加空白字符
    func test_UnitTestingBootcampViewModel_dataArray_shouldNotAddBlankString(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        vm.addItem(item: "")
        
        // Then 断言 = 判定
        XCTAssertTrue(vm.dataArray.isEmpty)
    }
    
    /// 单元测试函数名 根据命名规则命名 - 数组_预期值:添加空白字符
    func test_UnitTestingBootcampViewModel_dataArray_shouldNotAddBlankString2(){
        // Given
        guard let vm = viewModel else {
            XCTFail()
            return
        }
        
        // When
        vm.addItem(item: "")
        
        // Then 断言 = 判定
        XCTAssertTrue(vm.dataArray.isEmpty)
    }
    
    /// 单元测试函数名 根据命名规则命名 - 选中项_预期值:开始为空
    func test_UnitTestingBootcampViewModel_selectedItem_shouldStartAsNil(){
        // Given
        
        // When
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // Then 断言 = 判定
        XCTAssertTrue(vm.selectedItem == nil)
        XCTAssertNil(vm.selectedItem)
    }
    
    /// 单元测试函数名 根据命名规则命名 - 选中项_预期值:应该为空 当选择无效项
    func test_UnitTestingBootcampViewModel_selectedItem_shouldBeNilWhenSelectingInvalidItem(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // Select valid item : 选择有效项
        let newItem = UUID().uuidString
        vm.addItem(item: newItem)
        vm.selectItem(item: newItem)
        
        // Select invalid item : 选择无效项
        // When
        vm.selectItem(item: UUID().uuidString)
        
        // Then 断言 = 判定
        XCTAssertNil(vm.selectedItem)
    }
    
    /// 单元测试函数名 根据命名规则命名 - 选中项_预期值:应该选中
    func test_UnitTestingBootcampViewModel_selectedItem_shouldBeSelected(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let newItem = UUID().uuidString
        vm.addItem(item: newItem)
        vm.selectItem(item: newItem)
        
        // Then 断言 = 判定
        XCTAssertNotNil(vm.selectedItem)
        XCTAssertEqual(vm.selectedItem, newItem)
    }
    
    /// 单元测试函数名 根据命名规则命名 - 选中项_预期值:选中_压力测试
    func test_UnitTestingBootcampViewModel_selectedItem_shouldBeSelected_stress(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let loopCount: Int = Int.random(in: 1..<100)
        var itemsArray: [String] = []
        
        for _ in 0 ..< loopCount {
            let newItem = UUID().uuidString
            vm.addItem(item: newItem)
            itemsArray.append(newItem)
        }
        
        // 随机取一个字符串
        let randomItem = itemsArray.randomElement() ?? ""
        // 检查字符串不为空
        XCTAssertFalse(randomItem.isEmpty)
        vm.selectItem(item: randomItem)
        
        // Then 断言 = 判定
        XCTAssertNotNil(vm.selectedItem)
        XCTAssertEqual(vm.selectedItem, randomItem)
    }
    
    /// 单元测试函数名 根据命名规则命名 - 保存项_预期值:输出错误异常_元素没找到
    func test_UnitTestingBootcampViewModel_saveItem_shouldThrowError_itemNotFound(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let loopCount: Int = Int.random(in: 1..<100)
        for _ in 0 ..< loopCount {
            vm.addItem(item: UUID().uuidString)
        }
        
        // Then 断言 = 判定
        XCTAssertThrowsError(try vm.saveItem(item: UUID().uuidString))
        XCTAssertThrowsError(try vm.saveItem(item: UUID().uuidString), "Should throw Item Not Found error!") { error in
            // 返回错误
            let returnedError = error as? UnitTestingBootcampViewModel.DataError
            // 判断错误是否相同
            XCTAssertEqual(returnedError, UnitTestingBootcampViewModel.DataError.itemNotFound)
        }
    }
    
    /// 单元测试函数名 根据命名规则命名 - 保存项_预期值:输出错误异常_没数据
    func test_UnitTestingBootcampViewModel_saveItem_shouldThrowError_noData(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let loopCount: Int = Int.random(in: 1..<100)
        for _ in 0 ..< loopCount {
            vm.addItem(item: UUID().uuidString)
        }
        
        // Then 断言 = 判定
        do {
            try vm.saveItem(item: "")
        } catch let error {
            // 返回错误
            let returnedError = error as? UnitTestingBootcampViewModel.DataError
            // 判断错误是否相同
            XCTAssertEqual(returnedError, UnitTestingBootcampViewModel.DataError.noData)
        }
    }
    
    /// 单元测试函数名 根据命名规则命名 - 保存项_预期值:保存选项
    func test_UnitTestingBootcampViewModel_saveItem_shouldSaveItem(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let loopCount: Int = Int.random(in: 1..<100)
        var itemsArray: [String] = []
        
        for _ in 0 ..< loopCount {
            let newItem = UUID().uuidString
            vm.addItem(item: newItem)
            itemsArray.append(newItem)
        }
        
        // 随机取一个字符串
        let randomItem = itemsArray.randomElement() ?? ""
        // 检查字符串不为空
        XCTAssertFalse(randomItem.isEmpty)
        // Then 断言 = 判定
        XCTAssertNoThrow(try vm.saveItem(item: randomItem))
        do {
            try vm.saveItem(item: randomItem)
        } catch  {
            XCTFail()
        }
    }
    
    /// 单元测试函数名 根据命名规则命名 - 下载数据_预期值:返回选项
    func test_UnitTestingBootcampViewModel_downloadWithEscaping_shouldReturnItems(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let expectation = XCTestExpectation(description: "Should return items after 3 seconds")
        // dropFirst: 删除第一个发布 数组值,因为初始化为空数组,取的是第二个数组,模拟服务数据返回的数组
        vm.$dataArray
            .dropFirst()
            .sink { returnedItems in
                expectation.fulfill()
            }
            .store(in: &cancellables)
        
        vm.downloadWithEscaping()
        
        // Then 断言 = 判定 GreaterThan:大于
        // 为了安全获取到值,设置等待 5 秒
        wait(for: [expectation], timeout: 5)
        XCTAssertGreaterThan(vm.dataArray.count, 0)
    }
    
    /// 单元测试函数名 根据命名规则命名 - 下载数据组合_预期值:返回选项
    func test_UnitTestingBootcampViewModel_downloadWithCombine_shouldReturnItems(){
        // Given
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random())
        
        // When
        let expectation = XCTestExpectation(description: "Should return items after a seconds")
        // dropFirst: 删除第一个发布 数组值,因为初始化为空数组,取的是第二个数组,模拟服务数据返回的数组
        vm.$dataArray
            .dropFirst()
            .sink { returnedItems in
                expectation.fulfill()
            }
            .store(in: &cancellables)
        
        vm.downloadWithCombine()
        
        // Then 断言 = 判定 GreaterThan:大于
        // 为了安全获取到值,设置等待 5 秒
        wait(for: [expectation], timeout: 5)
        XCTAssertGreaterThan(vm.dataArray.count, 0)
    }
    
    /// 单元测试函数名 根据命名规则命名 - 下载数据组合_预期值:返回选项
    func test_UnitTestingBootcampViewModel_downloadWithCombine_shouldReturnItems2(){
        // Given
        let items: [String] = [UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString]
        let dataService: NewDataServiceProtocol = NewMockDataService(items: items)
        let vm = UnitTestingBootcampViewModel(isPremium: Bool.random(), dataService: dataService)
        
        // When
        let expectation = XCTestExpectation(description: "Should return items after a seconds")
        // dropFirst: 删除第一个发布 数组值,因为初始化为空数组,取的是第二个数组,模拟服务数据返回的数组
        vm.$dataArray
            .dropFirst()
            .sink { returnedItems in
                expectation.fulfill()
            }
            .store(in: &cancellables)
        
        vm.downloadWithCombine()
        
        // Then 断言 = 判定 GreaterThan:大于
        // 为了安全获取到值,设置等待 5 秒
        wait(for: [expectation], timeout: 5)
        XCTAssertGreaterThan(vm.dataArray.count, 0)
        XCTAssertEqual(vm.dataArray.count, items.count)
    }
}

3. 模拟请求数据 单元测试

  3.1 创建模拟请求数据类 NewMockDataService.swift

import Foundation
import SwiftUI
import Combine

/// 定义协议
protocol NewDataServiceProtocol{
    func downloadItemsWithEscaping(completion: @escaping (_ items: [String]) -> ())
    func downloadItemsWithCombine() -> AnyPublisher<[String], Error>
}

/// 实现模拟请求数据
class NewMockDataService: NewDataServiceProtocol {
    let items: [String]
    
    init(items: [String]?) {
        self.items = items ?? [
            "ONE", "TWO", "THREE"
        ]
    }
    
    /// 模拟网络下载数据 escaping: 转义字符
    func downloadItemsWithEscaping(completion: @escaping (_ items: [String]) -> ()) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            completion(self.items)
        }
    }
    
    /// 下载组合
    func downloadItemsWithCombine() -> AnyPublisher<[String], Error> {
        // 数据转换
        Just(self.items)
            .tryMap({ publishedItems in
                guard !publishedItems.isEmpty else {
                    throw URLError(.badServerResponse)
                }
                return publishedItems
            })
            .eraseToAnyPublisher()
    }
}

  3.2 创建单元测试类 NewMockDataService_Tests.swift

import XCTest
import Combine
/// 导入项目
@testable import SwiftfulThinkingAdvancedLearning

final class NewMockDataService_Tests: XCTestCase {
    /// 随时取消控制器
    var cancellable = Set<AnyCancellable>()
    
    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        cancellable.removeAll()
    }
    
    //  单元测试函数名 根据命名规则命名 - 测试_类名_初始化_预期值:正确的设置值
    func test_NewMockDataService_init_doesSetValuesCorrectly() {
        // 执行
        // Given: 给定
        let items: [String]? = nil
        let items2: [String]? = []
        let items3: [String]? = [UUID().uuidString, UUID().uuidString]
        
        // When: 时间
        let dataService = NewMockDataService(items: items)
        let dataService2 = NewMockDataService(items: items2)
        let dataService3 = NewMockDataService(items: items3)
        
        // Then 然后
        XCTAssertFalse(dataService.items.isEmpty)
        XCTAssertTrue(dataService2.items.isEmpty)
        XCTAssertEqual(dataService3.items.count, items3?.count)
    }
    
    //  单元测试函数名 根据命名规则命名 - 测试_类名_下载转换数据项_预期值:正确的设置值
    func test_NewMockDataService_downloadItemsWithEscaping_doesReturnValues() {
        // 执行
        // Given: 给定
        let dataService = NewMockDataService(items: nil)
        
        // When: 时间
        var items: [String] = []
        let expectation = XCTestExpectation()
        dataService.downloadItemsWithEscaping { returnedItems in
            items = returnedItems
            expectation.fulfill()
        }
        
        // Then 然后
        // 等待 5 秒
        wait(for: [expectation], timeout: 5)
        // 断言两个数组大小一样
        XCTAssertEqual(items.count, dataService.items.count)
    }
    
    //  单元测试函数名 根据命名规则命名 - 测试_类名_下载数据项组合_预期值:正确的设置值
    func test_NewMockDataService_downloadItemsWithCombine_doesReturnValues() {
        // 执行
        // Given: 给定
        let dataService = NewMockDataService(items: nil)
        
        // When: 时间
        var items: [String] = []
        let expectation = XCTestExpectation()
        
        // 下载组合控制
        dataService.downloadItemsWithCombine()
            .sink { completion in
                switch completion{
                case .finished:
                    expectation.fulfill()
                case .failure:
                    XCTFail()
                }
            } receiveValue: {returnedItems in
                // fulfill: 完成
                items = returnedItems
            }
            .store(in: &cancellable)
        // Then 然后
        // 等待 5 秒
        wait(for: [expectation], timeout: 5)
        // 断言两个数组大小一样
        XCTAssertEqual(items.count, dataService.items.count)
    }
    
    //  单元测试函数名 根据命名规则命名 - 测试_类名_下载数据项组合_预期值:确实失败
    func test_NewMockDataService_downloadItemsWithCombine_doesFail() {
        // 执行
        // Given: 给定
        let dataService = NewMockDataService(items: [])
        
        // When: 时间
        var items: [String] = []
        let expectation = XCTestExpectation(description: "Does throw an error")
        let expectation2 = XCTestExpectation(description: "Does throw URLError.badServerResponse")
        // 下载组合控制
        dataService.downloadItemsWithCombine()
            .sink { completion in
                switch completion{
                case .finished:
                    XCTFail()
                case .failure(let error):
                    expectation.fulfill()
                    
                    //let urlError = error as? URLError
                    // 断言,判定
                    //XCTAssertEqual(urlError, URLError(.badServerResponse))
                    
                    // 错误判断
                    if error as? URLError == URLError(.badServerResponse) {
                        expectation2.fulfill()
                    }
                }
            } receiveValue: {returnedItems in
                // fulfill: 完成
                items = returnedItems
            }
            .store(in: &cancellable)
        // Then 然后
        // 等待 5 秒
        wait(for: [expectation, expectation2], timeout: 5)
        // 断言两个数组大小一样
        XCTAssertEqual(items.count, dataService.items.count)
    }
}

4. 创建单元测试 View,调用测试的 ViewModel UnitTestingBootcampView.swift

import SwiftUI

/*
 1. Unit Test : 单元测试
 - test the business logic in your app : 测试应用中的业务逻辑
 
 2. UI  Test :  界面测试
 - test the UI of your app : 测试应用中的界面
 */

/// 单元测试
struct UnitTestingBootcampView: View {
    @StateObject private var vm: UnitTestingBootcampViewModel
    
    init(isPremium: Bool){
        _vm = StateObject(wrappedValue: UnitTestingBootcampViewModel(isPremium: isPremium))
    }
    
    var body: some View {
        Text(vm.isPremium.description)
    }
}

struct UnitTestingBootcampView_Previews: PreviewProvider {
    static var previews: some View {
        UnitTestingBootcampView(isPremium: true)
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1100838.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

win10安装nginx及简单使用(命令)

下载 下载地址&#xff1a;http://nginx.org/en/download.html 使用 解压 更改配置 conf目录下nginx.conf 修改为未被占用的端口&#xff0c;地址改成你的地址 server {# 监听端口 listen 9010;# 地址 server_name 127.0.0.1;# 静态资源location / {root html;i…

web前端开发基础---表格类页面

插入表格 <table>用于创建表格&#xff0c;<tr>表示表格的一行&#xff0c;<td>表示一个单元格 <td>与<th>标签的用法一致&#xff0c;往往<td>存储数据,<th>存储数据标题 <th>中的内容默认是加粗&#xff0c;居中显示的。…

智慧公厕管理系统:科技赋能城市公共卫生服务的便利

在现代社会的城市化进程中&#xff0c;公共设施的管理变得越来越重要。而公厕作为城市公共设施的重要组成部分&#xff0c;也需要借助科技的力量进行管理和监控。智慧公厕管理系统应运而生&#xff0c;它为公厕管理人员提供了实时监控和数据统计分析的功能&#xff0c;大大提高…

0基础学习VR全景平台篇第109篇:认识拼接软件PTGui Pro

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01;今天给大家讲解我们全景后期拼接软件PTgui pro&#xff0c;下面我们开始吧&#xff01; &#xff08;PTgui pro软件课程大纲&#xff09; 1.PTGui这个软件是什么 发明人 &#xf…

2023年中国建筑检测行业现状分析:国家政策推行[图]

建筑检测是指建设工程质量检测机构接受委托&#xff0c;依据国家有关法律、法规和工程建设强制性标准与相关规范&#xff0c;对涉及工程结构安全、使用功能和进入施工现场的建筑材料、构配件、设备的性能进行抽样检测和见证取样检测。 建设检测行业的下游主要是基础设施建设、房…

零售业:用这个小技巧,轻松搞定业绩!

自动售货机是一种现代化的零售解决方案&#xff0c;它已经深刻改变了我们购物的方式。不仅为消费者提供了更多的购物选择&#xff0c;还为企业提供了一种创新的销售渠道。 随着科技的不断进步&#xff0c;自动售货机已经从简单的零食和饮料销售机演化成了多功能的智能终端&…

俄罗斯YandexGPT 2在国家考试中获得高分;OpenAI API开发者快速入门指南

&#x1f989; AI新闻 &#x1f680; 俄罗斯YandexGPT 2聊天机器人成功在国家考试中获得高分 摘要&#xff1a;俄罗斯YandexGPT 2聊天机器人通过国家统一考试文学科目&#xff0c;以55分的加权分数成功进入大学。Yandex团队强调他们在开发过程中确保数据库不包含任何关于统考…

基于 ceph-deploy 部署 Ceph 集群

基于 ceph-deploy 部署 Ceph 集群 1、存储基础1.1单机存储设备1.2单机存储的问题1.3单机存储问题的解决方案1.3.1商业存储解决方案1.3.2分布式存储&#xff08;软件定义的存储 SDS&#xff09; 2、分布式存储2.1常见的分布式存储2.2分布式存储的类型 3、Ceph概述3.1Ceph简介3.2…

浅谈自媒体运营

文章目录 一、内容创作1.定位目标受众2.多元化的内容形式3.保持内容更新频率 二、推广渠道1.线上推广(1)微信公众号(2)微博(3)抖音、快手等短视频平台 2.线下推广 三、数据分析1.关注读者反馈2.分析数据 自媒体运营全攻略&#xff1a;文案写作流量打造个人品牌优势定位本书亮点…

同星智能为英飞凌TLE989X系列芯片提供刷写方案

一、方案概述 同星智能为英飞凌TLE989X系列芯片提供定制开发的代码包和刷写工具&#xff0c;主要包括代码包、基于TSMaster的刷写工程、刷写硬件工具TF1011等。 使用TF1011可以不需要英飞凌本身的烧录器&#xff0c;直接刷Bootram&#xff1b;也可以基于UDS刷APP。 代码包内容…

在Maven中配置代理服务器的详细教程

在Maven中配置代理服务器的详细教程如下&#xff1a; 首先&#xff0c;确保您已经安装了Maven。创建一个新的Maven项目。在命令行中输入以下命令&#xff1a; mvn archetype:generate -DgroupIdcom.example -DartifactIdmy-app -DarchetypeArtifactIdmaven-archetype-quickst…

ts使用记录

1、安装&#xff1a;通过管理员权权限使用cmd或者终端全局安装 npm install -g typescript2、运行&#xff1a; 可以通过tsc命令运行hello.ts文件 tsc hello.ts3、通过vscode的run code插件去右键运行 1.先安装插件run code 2.全局安装ts-node&#xff0c;npm install -g ts-n…

学习记录682@查准率与查全率真的必然负相关吗?

查准率和查全率定义 查准率与查全率真的必然负相关吗&#xff1f; 先说结论&#xff0c;两者并非绝对负相关&#xff0c;只是在统计学上表现出大概率的负相关性&#xff0c;而数学证明上无法严格证明两个的负相关性。 枚举来证明两者并非必然负相关 一组数据&#xff1a;A1、…

sip广播10W网络有源吸顶喇叭

SIP-7043 sip广播10W网络有源吸顶喇叭 一、描述 酒店背景音乐天花广播喇叭 SIP-7043是我司的一款SIP网络有源吸顶喇叭&#xff0c;具有10/100M以太网接口&#xff0c;内置有一个高品质扬声器&#xff0c;将网络音源通过自带的功放和喇叭输出播放&#xff0c;可达到功率10W。…

计算机操作系统-第八天

1、操作系统引导 什么是操作系统引导&#xff1f; 操作系统的引导就是当开机时&#xff0c;怎么让操作系统运行起来 操作系统引导的过程 分区表说明了磁盘中的每一个盘所占的内存空间的大小&#xff0c;以及它们的取值范围 ①在电脑开机后CPU执行位于ROM芯片中固定位置的引…

【AI视野·今日CV 计算机视觉论文速览 第265期】Wed, 11 Oct 2023

AI视野今日CS.CV 计算机视觉论文速览 Wed, 11 Oct 2023 Totally 88 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers AutoAD II: The Sequel -- Who, When, and What in Movie Audio Description Authors Tengda Han, Max Bain, Arsha Nagran…

Excel导入且进行数据校验

目录 ​​​​​​一、产品需求 二、解决方法 方案一&#xff1a;大量if-else判断校验 方案二&#xff1a;请求体加入注解进行校验 三、测试结果 一、产品需求 1.下载指定的excel数据模板 2.excel模板写入数据并导入 3.导入的时候根据校验规则进行筛选&#xff0c;导入…

防坠安全带上亚马逊合规认证合规标准是什么?如何办理?

防坠安全带 防坠安全带是一种防护装备&#xff0c;适合工人在高空作业时或在可能发生跌落的无防护边缘行走时穿着。防坠安全带设计用于包裹身体躯干&#xff0c;并将坠落力至少分布到大腿上部、骨盆、胸部和肩部。防坠安全带是固定物体与非固定物体之间的连接物&#xff0c;通…

WAILS安装

支持的平台 Windows 10/11 AMD64/ARM64 MacOS 10.13 AMD64 MacOS 11.0 ARM64 Linux AMD64/ARM64 依赖 Wails 有许多安装前需要的常见依赖项&#xff1a; Go 1.18 NPM (Node 15) Go 从 Go 下载页面 下载 Go。 确保您遵守官方的 Go 安装说明。 您还需要确保您的 PATH 环境变…

Unity中Shader的深度测试ZTest

文章目录 前言一、深度测试是干什么的二、图示讲解深度测试的作用三、深度值的测试操作1、设置为测试不通过&#xff0c;看看效果2、使用开关控制是否开启深度测试 前言 Unity中Shader的深度测试ZTest 一、深度测试是干什么的 通俗的讲&#xff0c;深度测试就是颜色在写入颜色…