自动化测试|我为什么从Cypress转到了Playwright?

以下为作者观点:

早在2019年,我就开始使用Cypress ,当时我所在的公司决定在新项目中放弃Protractor 。当时,我使用的框架是Angular,并且有机会实施Cypress PoC。最近,我换了工作,现在正在使用React,在那里我也有机会实现Playwright PoC。

个人感觉,有了Angular和React的经验,我更倾向于使用data-testid属性进行测试。这让我能够在UI端到端测试中保持一致的方法,而且我没有观察到Angular和React应用程序在测试中存在任何显著差异。

注:在本文中,我使用了一个React应用程序作为Cypress和Playwright的示例。

这两个测试框架都提供什么?

Cypress和Playwright都能够提供出色的UI测试体验(还可以测试API)。它们的自动等待功能让开发人员更容易编写测试,在测试运行时提供可视化用户界面,还能生成测试截图和视频,并支持类型脚本。

这两个框架都支持可视化组件测试,但我不会在本文中讨论这个主题。

由于这两个框架提供的功能非常相似,因此我将剖析每个框架是如何实现以下方面的,以及它们如何影响开发人员体验/工作效率的:

编写测试所用的语法对学习曲线和每个框架的整体易用性起着至关重要的作用。包括但不限于使用自定义命令扩展框架和记录测试。
测试的执行和可维护性是影响开发人员对测试的信心和调试时间的重要因素,特别是在速度和稳定性方面。
测试报告在测试过程中发挥着重要作用,评估其设置的难易程度及其提供的信息水平对于这两个框架都至关重要。

我的Cypress使用体验

安装Cypress非常简单,只需依赖NPM就可以了。没过多久就遇到了使用 Cypress 时需要了解的复杂细节。以下是一些主要细节:

● 用于编写测试的语法

Cypress使用类似Promise的语法来编写测试。乍一看这似乎并不令人困惑,但开发人员倾向于认为,因为他们的API看起来像promise(承诺),所以其行为也像promise(async/await,异步/等待)。可悲的现实是,事实并非如此,这导致开发人员花费大量时间学习如何使用Cypress API,并使其适合他们特定的测试场景。

如果需要使用async/await,你有两种选择:要么将其封装在Cypress命令中,以便添加到Cypress命令链中;要么使用cypress-promise这样的库。下面是每个选项的示例:

// async-await.spec.ts
import promisify from 'cypress-promise';

function sleep(milliseconds: number) {
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
}

async function asyncFunction(text: string) {
  console.log('started asyncFunction ' + text);
  await sleep(3000);
  console.log('finalized asyncFunction ' + text);
}

context('Async/Await Test', () => {
  beforeEach(() => {
    cy.visit('/');
  });

  it('convert promises into cypress commands, do not write tests using async/await', () => {
    cy.wrap(null).then(() => asyncFunction('first'));
    cy.wrap(null).then(() => asyncFunction('second'));
  });

  it('convert cypress commands to promises, should be able to code with async/await', async () => {
    const foo = await promisify(cy.wrap('foo'));
    const bar = await promisify(cy.wrap('bar'));
    expect(foo).to.equal('foo');
    expect(bar).to.equal('bar');
  });
});

● 测试报告

Cypress缺乏内置的测试报告功能,这意味着获取所有测试、测试持续时间以及故障截图和链接视频等附加元素的全面总结,可能是一个具有挑战性的繁琐过程。尽管在配置报告方面投入了大量精力,但在生成的报告中仍可能会出现缺少屏幕截图的情况。

图片

测试失败的基本 Cypress Mocha 测试报告

// package.json: example of cumbersome test reporting setup
  "scripts": {
    "-------------------- E2E Commands --------------------": "",
    "cypress:open": "nyc cypress open",
    "cypress:run": "npm-run-all -s --continue-on-error _clean _cypress-run:run _cypress-run:html",
    "-------------------- Supporting Commands --------------------": "",
    "_clean": "npx rimraf coverage cypress/output/junit cypress/output/mocha-json cypress/output/mocha-html/*.html cypress/output/mocha-html/*.json .nyc_output",
    "_coverage-report": "npx nyc report --reporter html",
    "_cypress-run:run": "nyc cypress run --headless --browser chrome",
    "_cypress-run:html:merge-json": "mochawesome-merge cypress/output/mocha-json/*.json > cypress/output/mocha-html/merged-mochawesome.json",
    "_cypress-run:html:gen-html-from-json": "marge cypress/output/mocha-html/merged-mochawesome.json -f cypress -o cypress/output/mocha-html -i true --charts true",
    "_cypress-run:html": "npm-run-all -s _cypress-run:html:merge-json _cypress-run:html:gen-html-from-json _coverage-report"
  },

● 如何运行head测试

Cypress会在其自己的浏览器应用程序中运行你的网络应用程序。它首先会打开一个页面,列出你的所有测试specs,然后你可以单击某个规范来运行该规范内的所有测试。我想补充的是,所有这一切都非常缓慢。此外,如果你只想在spec中运行一个测试,则需要将其标记为only,保存后只有该测试会自动重新加载。

图片

在Cypress浏览器内运行的应用程序

● 如何在headless运行中访问浏览器控制台日志

浏览器控制台日志只有在以标题形式(打开DevTools)运行测试时才可见。这意味着,如果你的测试在本地成功运行,但在CI管道上失败了,那么你要想把这些日志传到管道控制台就会很麻烦。幸运的是,有一个插件可以解决这个问题,但由于Cypress插件的工作方式,这不仅仅是一个即插即用的工作。

图片

只有在打开DevTools时才能看到浏览器控制台日志

// cypress/plugins/index.ts
interface Browsers {
 family: string;
 name: string;
}

interface LaunchOptions {
 args: string[];
}

const cypressPLugins = (on: unknown, config: unknown) => {
 require('@cypress/code-coverage/task')(on, config);
 // log console.* messages to the cypress console,
 // it helps when there are errors on the CI/CD pipeline
 require('cypress-log-to-output').install(on, consoleToLogConfig);
 require('@cypress/react/plugins/react-scripts')(on, config);
 // @ts-ignore
 on('before:browser:launch', (browser: Browsers, launchOptions: LaunchOptions) => {
 if (browser.family === 'chrome' || browser.name === 'chrome') {
 console.log('Adding chrome config...');
      launchOptions.args.push('--disable-dev-shm-usage');
      launchOptions.args.push('--lang=en');
    }
 return launchOptions;
  });
 return config;
};

export const consoleToLogConfig = (_type: unknown, event: { level: string; type: string }) => {
 // return true or false from this plugin to control if the event is logged on the cypress console
 // `type` is either `console` or `browser`
 // if `type` is `browser`, `event` is an object of the type `LogEntry`:
 //  https://chromedevtools.github.io/devtools-protocol/tot/Log/#type-LogEntry
 // if `type` is `console`, `event` is an object of the type passed to `Runtime.consoleAPICalled`:
 //  https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#event-consoleAPICalled

 // only show error events:
 return event.level === 'error' || event.type === 'error';
};

export default cypressPLugins;

● 调试测试(Debugging Tests)

Cypress中有几种不同的调试选项,由于Cypress命令是异步运行的,因此不能直接添加调试器(debugger)命令。

本质上,Cypress提供了2个有用的命令:debug()和pause()。前一个命令会向Cypress运行程序添加调试器命令,后一个命令则会在此时停止测试运行。两者都提供了检查DOM的能力,但只有使用 pause() 命令,你才能逐步检查测试中即将执行的每个Cypress 命令。

鉴于Cypress使用类似Promise的链接API,你可以将这些命令中的任何一个与任何Cypress命令链接起来:

cy.get([data-testid="username-input"]).type("my-username").pause();

图片

在Playwright中进行调试

● 测试并行化

Cypress不支持本地并行运行测试。有很多库可以帮助实现并行化,但是,这并不是一件容易的事。在我以前的公司中,我们尝试并行测试以提高流水线运行时间,但结果证明付出的努力太大,以至于我们取消了它的优先级。

副作用是,开发人员很少在本地运行完整的Cypress测试套件,他们只是等待来自管道的反馈。

● 速度

Cypress在headless和headed浏览器格式下运行时,速度都很慢,这是我们希望将测试并行化的主要原因。即使在本地运行,测试也非常慢。在开发测试时,当你修改文件时,测试会自动重新加载,即使在我的MacBook Pro上也需要几秒钟。

● 测试稳定性

Cypress以不稳定而闻名,主要是在CI/CD管道上,这导致开发人员花费大量时间去追寻ghosts。我看到开发人员通常采用的笨办法是在测试中添加 cy.wait(),并在CI/CD管道中添加重试。

● 自定义命令

如果你在测试中经常使用一些常用功能,那么你很可能想为此创建一个自定义Cypress命令。遗憾的是,添加此类命令既不直观,类型也不安全(除非你做了额外的工作):

// cypress/support/commands.ts
Cypress.Commands.add('getByTestId', (selector: string, ...args: unknown[]) => {
  return cy.get(`[data-testid=${selector}]`, ...args)
});

// cypress/typings/cypress.d.ts
declare namespace Cypress {
  interface Chainable {
    getByTestId(selector: string, ...args: unknown[]): Chainable;
  }
}

// you can now use this command in your test:
it('should type username in username input', () => {
  cy.getByTestId('username-input').type('my-username');
});

● 录音测试

Cypress现在提供Cypress Studio,目前这是一个实验性功能,我个人还没有尝试过。

我的Playwright使用体验

我从2023年初开始使用React,当时我的团队还没有任何UI测试。因此,我决定考虑引入Cypress。不过,我们也开始引入Web组件,并计划使用Storybook来记录和测试我们的Web组件。由于Storybook在幕后使用了Playwright,我研究了 Playwright可以提供什么。最初的诉求是:我的团队必须学习一个框架来测试Web组件和UI。

安装Playwright简直是轻而易举:不到一个小时,我就完成了所有测试。

● 编写测试所用的语法

编写Playwright测试就像编写普通的typescript代码一样简单,不需要学习特殊的API。最棒的是,你可以编写普通的async/await代码,因此你可以使用所有普通的typescript支持函数。比如:

import { test } from '@playwright/test';

test.describe('Playwright test with async/await', () => {
  function sleep(milliseconds: number) {
    return new Promise((resolve) => setTimeout(resolve, milliseconds));
  }

  async function asyncFunction(text: string) {
    console.log('started asyncFunction ' + text);
    await sleep(3000);
    console.log('finalized asyncFunction ' + text);
  }

  test('should open storybook and click around', async ({ page }) => {
    await page.goto('http://localhost:6006/');
    await page
      .getByRole('link', {
        name: 'Storybook 7.1.1 is available! Your current version is: 7.0.2 Dismiss notification',
      })
      .click();
    await page.getByRole('link', { name: 'Storybook' }).click();
    await page.locator('#internal-components-overview--docs').click();
  });

  test('should test the async methods used in previous example', async ({
    page,
  }) => {
    await asyncFunction('first');
    await asyncFunction('second');
  });
});

● 测试报告

这真是一个惊喜:我不需要做任何事情!

Playwright生成的开箱即用的报告非常棒。你还可以非常轻松地在多个浏览器上运行测试(只需更改配置,Playwright就会为你安装所需的浏览器)。

我将其配置为仅包含失败测试的跟踪信息、屏幕截图和视频;否则,就像 Cypress 一样,测试运行速度很慢。在下面的示例中,我们的第一次测试失败了。如果我们点击它,我们会得到以下信息:导致失败的异常、测试的哪些步骤失败、测试的视频以及完整的测试跟踪。

图片

Playwright HTML 报告概述

图片

测试失败的Playwright报告摘要

图片

Playwright测试轨迹

● 如何运行head测试

Playwright是微软开发的,所以他们当然提供了VS Code的插件。我自己是IntelliJ的用户,但我发现当我想运行Playwright测试时,我会切换到VS Code。

与Cypress不同的是,你不必启动任何程序就能运行一个或多个测试。只需在VS Code中打开代码,然后点击通常的单元测试绿色三角形,如果过去已经运行过测试,则点击绿勾/红X。你还可以选择打开浏览器或跟踪查看器。

开发人员在这里的体验非常棒。测试打开速度快,反应灵敏。

图片

● 如何在headless运行中访问浏览器控制台日志

与Cypress 一样,Playwright不会在Playwright运行的控制台中显示浏览器日志。为此,你可以扩展Playwright页面对象,将浏览器日志转发到控制台日志(还有其他方法,例如扩展测试对象本身)。

// utils/console.util.ts
export const configureLogForwarding = (page: Page) => {
  page.on('console', (msg) => {
    if (process.env.PLAYWRIGHT_LOG_TO_CONSOLE === 'true') {
      switch (msg.type()) {
        case 'info':
        case 'log': {
          // eslint-disable-next-line no-console
          console.log(`Log: "${msg.text()}"`);
          break;
        }
        case 'warning': {
          // eslint-disable-next-line no-console
          console.log(`Warning: "${msg.text()}"`);
          break;
        }
        case 'assert':
        case 'error': {
          // eslint-disable-next-line no-console
          console.log(`Error: "${msg.text()}"`);
          break;
        }
      }
    }
  });
};

// tests/demo-tests.spec.ts
test.describe('Playwright test with async/await', () => {
  test.beforeEach(async ({ page }) => {
    configureLogForwarding(page);
    hostAppNavigationPo = new HostAppNavigationPo(page);
    genericAssetModalPo = new GenericAssetModalPo(page);
  });
// ...

● 调试测试(Debugging Tests)

这是我最喜欢的功能之一。要调试测试,只需设置一个断点,然后右键单击绿色三角形/绿色滴点/红色x,再单击调试测试。浏览器将打开,运行将在断点处停止。从这里开始,就是开发人员习惯的正常调试会话。

图片

在Playwright中启动调试会话

图片

Playwright正在进行的调试会议

● 测试并行化

Playwright支持开箱即用的并行化(当然,你的被测系统当然必须能够支持并行运行的测试)。鉴于我们的CI/CD工具没有大量资源,因此速度很慢,因此我们在管道中关闭了并行测试。然而,当我编码时,我能够非常快速地在本地运行所有测试。当然,我们使用Playwright只有5个月左右,因此只有约80个测试。以下是一些非科学数据:~80个测试,在CI/CD中运行5分钟(1名工作人员),本地运行2分钟(1名工作人员),本地运行55秒(5名工作人员)。

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  /* other configuration... */
  /* Opt out of parallel tests on CI. */
  workers: process.env.CI ? 1 : undefined,
  /* Run tests in spec files in parallel */
  fullyParallel: true,
});

● 速度

当以headless形式运行等效测试时(就像在CI/CD管道中一样),Playwright比Cypress快约1.5倍。

此外,Playwright能够在不到一秒的时间内在浏览器上启动测试(在我的MacBook Pro上)。这意味着我可以随时以任何规格运行任何测试,而无需启动Playwright服务器等。与Cypress不同的是,你必须先启动Cypress UI,然后导航到你想在该UI中运行的测试。

这为开发者带来了绝佳的体验!

● 测试稳定性

过去5个月,我们一直在编写测试,还没有遇到任何不稳定的情况,也无需在测试中使用任何等待或休眠。由于我已不在原来使用Cypress的公司工作,我很难确定将那些不稳定的测试迁移到Playwright是否会使其稳定。

● 自定义命令

Playwright提供了一种扩展基础测试的方法,这样就可以在测试过程中轻松访问自定义命令和/或页面对象。这种模式简单易用、直观且类型安全。Playwright示例:

// my-test.ts
import { test as base } from '@playwright/test';
import { TodoPage } from './todo-page';

export type Options = { defaultItem: string };

// Extend basic test by providing a "defaultItem" option and a "todoPage" fixture.
export const test = base.extend<Options & { todoPage: TodoPage }>({
  // Define an option and provide a default value.
  // We can later override it in the config.
  defaultItem: ['Do stuff', { option: true }],

  // Define a fixture. Note that it can use built-in fixture "page"
  // and a new option "defaultItem".
  todoPage: async ({ page, defaultItem }, use) => {
    const todoPage = new TodoPage(page);
    await todoPage.goto();
    await todoPage.addToDo(defaultItem);
    await use(todoPage);
    await todoPage.removeAll();
  },
});

// example.spec.ts
import { test } from './my-test';

test('test 1', async ({ todoPage }) => {
  await todoPage.addToDo('my todo');
  // ...
});

● 录制测试

Playwright提供了使用VS Code插件录制UI测试的选项。你所需要做的就是按下Record new按钮,Playwright就会打开一个浏览器。然后输入网络应用程序的URL并开始点击。Playwright录制的最大优点是,如果存在data-testid选择器(await page.getByTestId(‘dialog-title’); ),它就会选择该选择器。

图片

Playwright 还有许多其他优点,我在本文中没有介绍,主要是因为我没有大量使用这些方面,但这里有一些示例:

● iFrames

Playwright可以与iFrames兼容,使用起来非常流畅。在我目前的工作中,我们正在使用iFrames,但在我之前的工作中(当时我在Cypress工作),我们没有使用 iFrames。不过,据我所知,你需要安装Cypress插件才能测试iFrames。

● Web-app服务器

Cypress和Playwright都要求你的应用程序在运行时才能进行测试。对Cypress的一个普遍要求是,该框架能够在运行测试前启动被测系统。我个人在本地和在CI/CD管道中运行测试时,应用程序始终处于运行状态。不过,Playwright也听到了开发人员的愿望:

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  // Run your local dev server before starting the tests.
  webServer: {
    command: 'npm run start',
    url: 'http://127.0.0.1:3000',
    reuseExistingServer: !process.env.CI,
  },
});

● Forbid only关键字

一个常见的用例是,当开发人员想要运行单个测试时,他们将其标记为only. 不幸的是,他们经常忘记在提交之前删除它。Playwright附带了一个配置来检测这一点,而使用Cypress时我们必须添加eslint规则。

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  /* Fail the build on CI if you accidentally left test.only in the source code. */
  forbidOnly: !!process.env.CI,
});

// example.spec.ts
test.describe('Playwright test with async/await', () => {

  test.only('should test the async methods used in previous example', async ({
    page,
  }) => {
    await asyncFunction1();
    await asyncFunction2();
  });

// more tests...

● 多页面

Cypress在其自己的Web应用程序内运行Web应用程序,这会限制Cypress一次只能在一页上运行测试。另一方面,Playwright可在每个浏览器中打开多个BrowserContext和/或多个页面,所有这些页面都有不同的网站/域等,并可在所有这些页面上运行测试。

● 多语言支持

在Cypress中,您可以选择使用JavaScript或TypeScript编写测试。然而,在Playwright中,编写测试的语言选项更加多样化。你可以选择使用JavaScript、TypeScript、Java、Python或 .NET编写测试,从而为开发人员提供了更大的灵活性,让他们可以使用自己喜欢的编程语言来实现测试自动化。

结论

多年来,我一直是Cypress的粉丝,也是UI测试的坚定拥护者,现在要开始使用一个我不确定是否会像Cypress一样优秀的新框架,这并不是一个容易的决定。尽管如此,我还是惊喜地发现Playwright不仅达到了Cypress的预期,而且在我能想到的所有方面都超过了Cypress。

最后,Cypress和Playwright的开发者社区都相当庞大。尽管Cypress仍然更受欢迎,但随着越来越多的开发者发现Playwright的开发者体验是如此令人惊叹,Playwright社区也在快速发展。

在这里插入图片描述

截至2023年7月29日的对比数据

建议任何已经在使用Cypress或正在考虑进入UI测试领域的人,将Playwright作为一个值得考虑的选择。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MEFLUT: Unsupervised 1D Lookup Tables for Multi-exposure Image Fusion

Abstract 在本文中&#xff0c;我们介绍了一种高质量多重曝光图像融合&#xff08;MEF&#xff09;的新方法。我们表明&#xff0c;曝光的融合权重可以编码到一维查找表&#xff08;LUT&#xff09;中&#xff0c;该表将像素强度值作为输入并产生融合权重作为输出。我们为每次…

涵盖多种功能,龙讯旷腾Module第一期:物质结构

Module是什么 在PWmat的基础功能上&#xff0c;我们针对用户的使用需求开发了一些顶层模块&#xff08;Module&#xff09;。这些Module中的一部分是与已有的优秀工具的接口&#xff0c;一部分是以PWmat的计算结果为基础得到实际需要的物理量&#xff0c;一部分则是为特定的计…

预算削减与经济动荡:2024 年明智且经济地创新

如何在经济衰退周期中保持创新&#xff1f;这篇创新研究提供了实用建议。在经济下行压力下领导者往往会试图降低成本和维持生存。然而&#xff0c;这种二元对立的压力往往会导致领导者做出不够理想的决策&#xff0c;更多地关注生存而不是未来投资。本文提供了一系列实用的建议…

PC行内编辑

点击编辑&#xff0c;行内编辑输入框出现&#xff0c;给列表的每条数据定义编辑标记&#xff0c;最后一定记得 v-model双向绑定&#xff0c;使数据回显。 步骤&#xff1a; 1、给行数据定义编辑标记 2、点击行编辑标记&#xff08;isedit&#xff09; 3、插槽根据标记渲染表单 …

Redis大key与热Key

什么是 bigkey&#xff1f; 简单来说&#xff0c;如果一个 key 对应的 value 所占用的内存比较大&#xff0c;那这个 key 就可以看作是 bigkey。具体多大才算大呢&#xff1f;有一个不是特别精确的参考标准&#xff1a; bigkey 是怎么产生的&#xff1f;有什么危害&#xff1f;…

408—电子笔记分享

一、笔记下载 链接&#xff1a;https://pan.baidu.com/s/1bFz8IX6EkFMWTfY9ozvVpg?pwddeng 提取码&#xff1a;deng b站视频&#xff1a;408-计算机网络-笔记分享_哔哩哔哩_bilibili 包含了408四门科目&#xff08;数据结构、操作系统、计算机组成原理、计算机网络&#xff09…

Python交互式解释器及用法

为了让开发者能快速学习、测试 Python 的各种功能&#xff0c;Python 提供的“python”命令不仅能用于运行 Python 程序&#xff0c;也可作为一个交互式解释器一一开发者逐行输入 Python 代码&#xff0c;它逐行解释执行。 当输入“python”命令时&#xff0c;可以看到如下输出…

如何生成唯一ID:探讨常用方法与技术应用

文章目录 1. UUID&#xff08;Universally Unique Identifier&#xff09;2. 数据库自增ID3. Twitter的Snowflake算法4. 数据库全局唯一ID&#xff08;Global Unique Identifier&#xff0c;GUID&#xff09;结语 &#x1f389;如何生成唯一ID&#xff1a;探讨常用方法与技术应…

steam搬砖如何选品?选品软件和教程靠谱吗?

说到steam搬砖项目&#xff0c;目前平台最火的就是CSGO游戏搬砖。在steam搬砖项目中&#xff0c;选品是一个至关重要的环节&#xff0c;直接影响到利润。而选品软件可以帮助我们更快地了解市场变化、计算成本利润等关键信息&#xff0c;提高选品的效率和准确性。可靠的选品软件…

MySQL学习day03

一、SQL图形化界面工具 常用比较常用的图形化界面有sqlyog、mavicat、datagrip datagrip工具使用相当方便&#xff0c;功能比前面两种都要强大。 DataGrip工具的安装和使用请查看这篇文档&#xff1a;DataGrip 安装教程 DML-介绍 DML全称是Data Manipulation Language(数据…

硬质金属件去毛刺技术,机械臂去毛刺主轴是核心

作为一种先进且高效的自动化去毛刺技术&#xff0c;机械臂去毛刺主轴在制造业中&#xff0c;特别是金属加工和汽车零部件加工中得到了广泛的应用&#xff0c;通过高速旋转的主轴和精确控制的机械臂实现高精度、高效率、高质量的自动化去毛刺作业。机械臂去毛刺技术是通过主轴的…

40.0/jdbc/Java数据连接/jar包运用增删改

目录 40.1. 回顾 40.2. 正文 40.1 为什么需要jdbc 40.2 如何连接mysql数据库 40 .3 jdbc容易出现的错误 40.4 完成删除 40.5 完成修改 40.1. 回顾 1. 自联查询: 自己连接自己的表。注意:一定要为表起别名。 2. 嵌套查询: 把一个查询的结果作为另一个查询的条件值。 3. 组…

基于C#实现十字链表

上一篇我们看了矩阵的顺序存储&#xff0c;这篇我们再看看一种链式存储方法“十字链表”&#xff0c;当然目的都是一样&#xff0c;压缩空间。 一、概念 既然要用链表节点来模拟矩阵中的非零元素&#xff0c;肯定需要如下 5 个元素(row,col,val,down,right)&#xff0c;其中&…

Unity之NetCode多人网络游戏联机对战教程(10)--玩家动画同步

文章目录 前言NetworkAnimation服务端权威客户端权威 前言 这次的动画同步与位置同步&#xff0c;可以说实现思路是一样的&#xff0c;代码相似度也非常高 NetworkAnimation 如果直接挂载这个脚本只有Host&#xff08;服务端&#xff09;才可以同步&#xff0c;Client是没有…

视频封面:视频图片提取技巧,从指定时长中捕捉需求的图片

在当今的数字时代&#xff0c;视频已成为日常生活中不可或缺的一部分。无论是社交媒体、博客&#xff0c;视频都发挥着重要的作用。而一个吸引的视频封面往往能吸引更多的观众点击观看&#xff0c;选择清晰度高、色彩鲜艳且能吸引人的图片。同时&#xff0c;确保图片与视频内容…

MySQL的Linux安装

在MySQL官网下载压缩包MySQL :: Download MySQL Community Server (Archived Versions) 下载完成后将压缩包上传到Linux中。我这里是下的CentOS的压缩包。 并且用的是FinalShell连接工具&#xff0c;可以选择压缩包直接上传。 ​ 上传完毕后&#xff0c;新建mysql文件夹&…

计算机视觉面试题-03

1、简单介绍一下sigmoid&#xff0c;relu&#xff0c;softplus&#xff0c;tanh&#xff0c;RBF及其应用场景 这里简单介绍几个激活函数及其应用场景&#xff1a; Sigmoid 函数&#xff08;Logistic 函数&#xff09;&#xff1a; 公式&#xff1a; s i g m a ( x ) 1 1 e …

【香橙派】实战记录2——烧录安卓镜像及基本功能

文章目录 一、安卓烧录二、安卓基本功能1、蓝牙2、相机功能3、投屏 一、安卓烧录 检查环境&#xff1a;检查PC系统&#xff0c;确保有Microsoft Visual C 2008 Redistrbutable - x86&#xff0c;否则在官网下载的官方工具 - 安卓镜像烧录工具里运行vcredist_x86.exe。 插入存储…

模板上新|2023年10月DataEase模板市场上新动态

DataEase开源数据可视化分析平台于2022年6月正式发布模板市场&#xff08;https://dataease.io/templates/&#xff09;。模板市场旨在为DataEase用户提供专业、美观、拿来即用的仪表板模板&#xff0c;方便用户根据自身的业务需求和使用场景选择对应的仪表板模板&#xff0c;并…

Authing CEO 谢扬来信 |我的原则

从忙碌的工作中短暂抽身&#xff0c;有很多感想&#xff0c;不吐不快&#xff0c;借此机会&#xff0c;倾我所有&#xff0c;诉我原则。 原则一&#xff1a;坚强信念&#xff0c;坚定意志 商人大多「无利不起早」&#xff0c;而创业者的反馈周期比商人长非常非常多。 相比「商品…