新闻详情

新闻详情

首页 / 资讯中心 / 详情

Java单元测试实战:从@Test注解到JUnit 5与IDEA调试

发布时间:2026/10/1 11:22:47来源:尧图网络
Java单元测试实战:从@Test注解到JUnit 5与IDEA调试
1. 为什么写Test告别main方法里的临时验证做Java开发的朋友几乎都会经历一个阶段想验证某段代码逻辑到底对不对就打开一个类写个main方法new一个对象调一下方法然后用System.out打印结果。看完没问题再把main方法删掉或者注释掉留着下次用。这套流程在项目初期、代码量小的时候没什么问题但项目一旦跑起来类的依赖关系变复杂方法里有数据库操作、有远程调用、有缓存读写你就会发现main方法根本调不动或者要准备一大堆前置条件。这时候单元测试就成了唯一的解法而Test注解就是单元测试的入口。Test放在方法上意思是告诉JUnit框架这是一个测试方法你可以在IDEA里单独运行它也可以批量运行整个类里的所有测试方法。它的价值不只是“能跑”而是“随时能跑、快速反馈”。改一行代码按一下快捷键几秒钟内就知道有没有把原来的逻辑改坏。这种反馈速度是main方法远远给不了的。我自己的体会是早期写Test纯粹是为了应付公司覆盖率要求把方法调一遍断言写一句就完事。后来在一次重构老模块时我改了一个工具的排序算法因为完全没有测试保护上线后线上数据出现问题排查了两个小时才定位到是排序不稳定导致的。那次之后凡是有业务逻辑的方法我一定先补测试再动手改。这套思维转变过来Test就不再是个注解而是你改代码时的安全网。所以在IDEA里用好Test其实不只是一个操作技巧问题更是一套“让代码变得可验证”的工作习惯问题。这篇文章不打算只讲“右键点击运行”这种基础操作而是把Test从环境搭建、常用写法、IDEA运行机制到Maven集成的完整链路都梳理清楚。你在看的过程中可以边看边在自己的项目里操作看完之后基本能从“会用”变成“用得顺手”。2. 环境准备IDEA、Maven和JUnit之间的那点事2.1 为什么你的项目里test标红很多新手第一次遇到的情况是注解明明写对了import也加上了但编辑器里Test三个字母还是标红报错信息是“Cannot resolve symbol ‘Test’”。这个问题的本质是你的代码里还缺少JUnit的依赖包。Java项目不像IDE内置的某些功能它本身并不知道JUnit是什么你要在项目里明确声明“我要用JUnit”构建工具才会把对应的jar包拉下来放进classpath里。这时候你可能会问为什么有的项目新建出来就能用Test有的就不行区别在于创建项目的方式。如果你用IDEA自带的Spring Initializr创建Spring Boot项目勾选了测试依赖Maven的pom.xml里会自动加上spring-boot-starter-test这个starter里面就集成了JUnit 5所以开箱即用。但如果你创建的是普通的Java项目或者通过Maven骨架生成的项目就需要手动添加JUnit依赖。2.2 手动配置JUnit 5依赖的两种方式我以Maven项目为例推荐的方式很简单在pom.xml里加上下面这段dependency groupIdorg.junit.jupiter/groupId artifactIdjunit-jupiter/artifactId version5.10.2/version scopetest/scope /dependency注意几个关键点scope为test表示这个依赖只在测试编译和运行阶段生效不会打包进生产环境。junit-jupiter是聚合依赖它包含了junit-jupiter-api写测试用到的注解和断言、junit-jupiter-engineJUnit 5测试引擎、junit-jupiter-params参数化测试支持一次性全给齐。版本要和你项目里的其他依赖兼容如果你的项目还在用Spring 5.xJUnit 5.4到5.8一般都没问题用Spring Boot 2.5以上建议直接配5.7或更高版本。如果你用的是Gradle则在build.gradle里这样写testImplementation org.junit.jupiter:junit-jupiter:5.10.2还有一种特殊情况公司内部的私有仓库同步不到Maven中央仓库的最新版本那你就要看你自己项目里其他Spring依赖的版本尽量保持一致避免引入版本冲突。配完之后记得在IDEA里点一下Maven面板里的刷新按钮Reload All Maven Projects让依赖真正进入classpath。2.3 JUnit 4和JUnit 5的差异选哪个这也是新手容易迷糊的地方。你在网上搜Test相关教程可能搜到JUnit 4的写法import的是org.junit.Test注解的含义和用法差不多但底层机制和推荐写法有不少区别。JUnit 4老版本import org.junit.Test; import static org.junit.Assert.assertEquals;JUnit 5新版官方主推import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals;两者的核心区别我整理成了一张对比表对比项JUnit 4JUnit 5包名org.junitorg.junit.jupiter断言类AssertAssertions生命周期注解BeforeClass / AfterClassBeforeAll / AfterAll前后置方法Before / AfterBeforeEach / AfterEach参数化测试需额外引入功能内置支持写法更简洁测试引擎单一引擎Jupiter引擎 平台可扩展如果你的项目之前用的是JUnit 4想直接升到JUnit 5要注意包名全都要改Before这种注解也要换成BeforeEach否则测试类能编译但运行的时候方法根本不会执行。我个人建议新项目直接用JUnit 5Spring Boot 2.2版本以后默认集成的就是JUnit 5没必要再往回踩JUnit 4的坑。2.4 测试目录的结构src/test/java不是随便建的IDEA里跑Test之前还要保证你的测试代码放在正确的目录里。Maven标准格式下测试代码放在src/test/java目录测试资源放在src/test/resources目录主代码放在src/main/java目录。这个目录结构决定了mvn test命令能不能识别到你的测试类。常见的坑有两个把测试类写在src/main/java里还能正常运行但违反了工程规范而且打生产包的时候测试代码也会被编译进去。建了src/test/java但IDEA没有把它标记为“Test Sources Root”导致代码里可以写Test但右键没有Run选项或者Maven跑测试时扫描不到。如果出现后面这种情况解决办法很简单在IDEA里找到src/test/java目录右键 - Mark Directory as - Test Sources Root。IDEA会把这个目录变成绿色表示它已经被识别为测试源目录。做完这一步测试类上会出现可运行的绿色箭头mvn test也能正常扫描到。3. Test的核心用法从冒烟用例到完整断言体系3.1 一个最基本的Test方法长什么样先写一个最简单的测试类感受一下整体结构import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; public class CalculatorTest { Test void testAdd() { Calculator calculator new Calculator(); int result calculator.add(2, 3); assertEquals(5, result); } }这里要把几个点拆开理解方法名是任意的不需要以test开头JUnit 3时代的约定JUnit 5完全不需要。方法必须是实例方法不能是staticJUnit会为每个测试方法创建一个新的测试类实例保证方法之间互不干扰。方法返回值必须是void有返回值的话JUnit会直接报错。assert的导入是静态导入写的assertEquals、assertTrue这些实际上是Assertions类里的静态方法。Assertions这个类可以说是Tenant的核心搭档。它提供了一系列断言方法用来验证实际结果是否符合预期。如果断言失败测试就会以一个红色的状态结束并且会在控制台里告诉你期望值和实际值差了多少。我举个最常见的场景在测一个字符串工具类时Test void testTruncate() { String result StringUtil.truncate(Hello World, 5); assertEquals(Hello, result); assertTrue(result.length() 5); assertNotNull(result); }3.2 断言方法该如何取舍我推荐这几个Assertions类里的断言方法有很多但日常开发真正高频使用的其实不超过十个。我把它们列出来按使用频率从高到低排断言方法作用适用场景assertEquals(expected, actual)判断两个值相等最通用测方法返回值assertTrue(condition)判断条件为true判断布尔结果assertFalse(condition)判断条件为false判断布尔结果assertNull(obj) / assertNotNull(obj)判断对象是否为null返回值是否为空assertArrayEquals(expected, actual)判断两个数组相等返回数组或列表转数组assertThrows(exceptionType, executable)判断是否抛出指定异常异常分支测试assertTimeout(duration, executable)判断是否在指定时间内完成性能下限测试assertIterableEquals(expected, actual)判断两个Iterable内容相等集合、列表断言用assertEquals的时候有一个细节容易忽略如果是比较两个double类型的值不能直接assertEquals(0.1, 0.2 - 0.1)因为浮点精度问题会直接导致失败。理想的做法是传入第三个参数delta比如assertEquals(0.1, 0.2 - 0.1, 0.000001);这个delta表示允许的误差范围等于告诉框架“只要两个数之间的差距在delta以内就算通过”。3.3 测试异常分支assertThrows的正确打开方式方法不仅要测正常路径异常路径更要测。比如一个除法的工具方法除数为0时要抛出IllegalArgumentException。你可能会这样写Test void testDivideByZero() { try { int result Calculator.divide(10, 0); fail(应该抛出异常但没有抛出); } catch (IllegalArgumentException e) { // 测试通过 } }这种写法虽然能行但fail()方法本身写得有点绕而且你没法精确判断异常信息。更推荐的方式是Test void testDivideByZero() { IllegalArgumentException exception assertThrows( IllegalArgumentException.class, () - Calculator.divide(10, 0) ); assertEquals(除数不能为0, exception.getMessage()); }assertThrows的两个参数第一个是期望的异常类型第二个是一个Executable函数式接口也就是Lambda表达式。测试逻辑如果抛出指定异常测试就通过如果没抛测试失败。把异常对象接收回来后还可以继续对异常信息做断言。多个异常分支放在一个测试方法里不是不行但那样如果前面断言失败后面的分支就测不到了。比较规范的做法是一个异常场景写一个Test方法这样测试报告里能明确看到“哪个方法测哪个异常分支”。3.4 生命周期注解BeforeEach和AfterEach写单元测试时如果每个测试方法都要创建一堆对象、准备一堆数据代码会非常臃肿。JUnit 5提供了几个生命周期注解来解决这个问题。BeforeEach每个测试方法执行之前都会运行一次。AfterEach每个测试方法执行之后都会运行一次。BeforeAll所有测试方法运行之前只运行一次方法必须为static。AfterAll所有测试方法运行之后只运行一次方法必须为static。我第一次理解这几个注解时把它们想象成“测试方法的前置动作和后置动作”。BeforeEach适合准备测试对象、初始化临时数据AfterEach适合清理资源、关闭连接。一个典型的场景是模拟数据库DAO测试public class UserDaoTest { Connection connection; BeforeEach void setUp() { connection DataSourceUtil.getConnection(); // 获取连接 } AfterEach void tearDown() throws Exception { connection.close(); // 每个用例测试完自动释放 } Test void testInsertUser() { UserDao userDao new UserDao(connection); userDao.insert(new User(张三)); assertEquals(1, userDao.count()); } Test void testDeleteUser() { UserDao userDao new UserDao(connection); userDao.delete(1L); assertEquals(0, userDao.count()); } }这样两个测试方法之间互不影响每次都是全新的连接和数据为后面的独立性打下了基础。如果你把这套机制用熟了会发现测试类和测试方法就会变得非常整洁。3.5 参数化测试一键测多组数据很多场景下同一个逻辑你要验证多组输入输出。比如一个判断闰年的方法你要测2020年闰年、2021年平年、2000年世纪闰年、1900年平年。如果用几个Test方法分别写代码会重复如果在一个方法里用for循环跑断言第一个数据失败后后面的就测不到了。参数化测试就是解决这个问题的public class LeapYearTest { ParameterizedTest ValueSource(ints {2020, 2000, 2024}) void testLeapYear(int year) { assertTrue(DateUtil.isLeapYear(year)); } ParameterizedTest ValueSource(ints {2021, 1900, 2100}) void testNotLeapYear(int year) { assertFalse(DateUtil.isLeapYear(year)); } }ValueSource是参数来源的一种还有CsvSource可以传多组参数MethodSource可以从指定方法读取数据。参数化测试最大的好处是每一组参数在结果面板里都会被当成一条独立的用例哪一组失败了看得清清楚楚不会因为第一组失败而跳过后面的验证。4. 在IDEA里跑起来运行方式、调试技巧和结果面板逐项拆解4.1 三种运行方式哪种更顺手IDEA运行Test的入口从易到难说方式一方法左侧的绿色箭头这是最直观的方式。测试方法前面会出现一个绿色箭头点击它会弹出菜单选择Run ‘testAdd()’就直接运行当前方法。如果测试类里没有绿色箭头大概率是测试目录没标记或者IDEA没识别到测试框架回到前面检查配置。方式二测试类上的绿色箭头点击测试类左侧的箭头会运行该类的所有Test方法。适合你要跑一个类里全部用例的场景。方式三快捷键运行在测试方法内部或类内部按CtrlShiftF10Windows/Linux或ControlShiftRMac直接运行当前上下文对应的测试。这里有一个很方便的小技巧即使你把光标放在测试方法的上一行或下一行IDEA也能根据上下文推断出你要跑的是当前类还是当前方法。用熟练后你会完全扔掉鼠标写测试的效率会上一个档次。4.2 调试测试方法断点调试和查看具体调用栈Test方法也能像普通的main方法一样打断点、单步调试。点击方法前绿色箭头旁边的“虫”图标Debug或按快捷键ShiftF9就能以调试模式运行当前测试。调试测试的典型场景是某个方法在所有测试里都失败了但报错信息不够直观。这时候在该方法里打上断点用Debug模式跑一遍就能看到方法内部每一步变量的变化、走到了哪个分支、返回值是什么。因为JUnit为每个测试方法创建独立实例你在调试窗口里看到的对象状态就是这样用例执行时的真实状态不会受到其他用例的干扰。有一点要注意如果测试方法中使用了BeforeEach方法断点打在测试方法体里不会自动触发前置阶段但调试的步骤流里能看到调用链经过哪些方法。结合IDEA的Frames面板你可以清楚地看到当前执行到哪个测试的哪一层调用。4.3 结果面板怎么看绿色、红灯和失败堆栈运行完测试后IDEA底部的Run面板会显示结果。这里面有几个信息很多人没有仔细看绿色对勾全部通过。红色感叹号至少有一个测试失败。分区展示的测试树左侧按类和方法展示点某个失败的方法右侧会展示完整的失败堆栈最常见的两类错误是AssertionFailedError断言失败代表期望值和实际值不一致和NullPointerException代码本身有问题。断言失败时消息里会明确写出expected和actual的值。比如expected: 5 but was: 5这样的信息已经足够定位了。但如果两值一样还失败那多半是比较了两个不同的对象引用这时候要用assertEquals对应重载方法。如果堆栈信息不够清晰你也可以在Run面板左下角勾选“Show Passed”来查看通过名单方便排查有没有漏跑的用例。另外一个工具是Covrage覆盖率运行在方法或类上右键选择Run with Coverage。运行完成后IDEA会用绿色已覆盖、黄色部分覆盖、红色未覆盖高亮代码行你一眼就能看出哪个if分支没有测到哪个方法连调都没被调用。这个功能在验证测试完整性时特别好用不是只有公司卡覆盖率时才能用。4.4 只跑一部分用例自定义Test运行配置项目大了以后测试类可能很多每次全量跑一遍要几分钟。IDEA允许你自定义运行配置只运行指定类或指定方法的组合。操作路径是Run - Edit Configurations - 左上角号 - JUnit - 在Test kind里选择“Class”或“Method”然后填上你要运行的测试类名或方法名。如果你是经常调试某个模块这个方法比每次在代码里找绿色箭头再点一下要快很多。还有一个场景同一个测试类里想跳过某个暂时失败的用例又不想删代码。可以用Disabled注解Disabled(待实现完毕后再启用) Test void testSomeFeature() { // ... }这样IDEA运行这个类时会自动跳过被标记的用例并且结果面板里会显示为“Skipped”跟失败和通过都区分开了。对于“暂时失败但还没有时间修”的用例这样做能让测试报告保持整洁不会因为一个红点影响你看其他用例的结果。5. 跑测试时的常见坑mvn test、Test Sources Root 和 surefire 的恩怨5.1 IDEA里能跑通命令行mvn test却报错一个非常典型的现象在IDEA里右键运行Test一切正常但在终端里执行mvn test报了一堆错或者是“No tests were executed”或者干脆编译失败。为什么会有这种差异因为IDEA运行测试时使用的是IDE自己维护的classpath和编译结果而mvn test是Maven在命令行里独立编译并运行。如果你的代码里引入了某些依赖但pom.xml里没有声明IDEA可能因为本地的某种缓存或项目结构的巧合能识别出来Maven那边就不吃这一套。更常见的原因是测试代码里用了JUnit 5的新特性但pom.xml里配的却是JUnit 4的依赖和插件。解决思路是以mvn test为准。写完测试后一定要在命令行里跑一次mvn test确保CI持续集成环境能复现同样的结果。这在多人协作时尤其重要因为每个人本地的IDEA状态可能都不一样但Maven的构建逻辑是一致的。还有一个小场景公司CI里的构建命令是mvn install这个命令默认会先跑全部测试。如果你只是打了个新功能测试还没写完CI失败就会卡住你。这时候可以临时跳过测试但不推荐用mvn install -DskipTests因为它的实际意思是“编译测试代码但不运行”测试代码如果编译有问题照样会失败。更彻底的说法是mvn install -DskipTests跳过测试执行但编译测试代码。mvn install -Dmaven.test.skiptrue跳过测试编译和执行最彻底。mvn install -DfailIfNoTestsfalse即使没有测试用例也不会报错适合某些特殊模块。通常我建议用-DskipTests因为这样至少能保证测试代码编译通过把一部分问题暴露在本地-Dmaven.test.skiptrue一般是临时救急用别养成习惯。5.2 maven-surefire-plugin 和“test failure”报错再往深一层Maven跑测试的核心依赖是maven-surefire-plugin。这个插件负责在build周期里找到测试类并调用JUnit引擎运行。如果你直接在Maven中央仓库拉了某个老版本的surefire插件而项目里的JUnit是5.10可能会遇到surefire不认识JUnit 5的Provider导致“No tests to run”或者干脆报错。怎么解决在pom.xml里显式指定surefire版本比如plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-surefire-plugin/artifactId version3.2.5/version /plugin当你执行mvn install时报“There are test failures”并附上surefire-report路径时实际上是把失败用例输出到了target/surefire-reports目录下的txt和xml文件里。这个报错信息经常让人困惑尤其是中文环境里可能看到“请参考...surefire...”的提示其实就是让人去翻那个目录下的报告。打开对应测试类的txt文件就能看到每个失败方法的堆栈和IDEA面板里的信息基本一致。了解这个机制后再遇到CI里“test failure”的邮件或日志你就不会慌了先去surefire-reports找全一点的堆栈定位失败原因再到本地用同一条命令复现。5.3 Test用错了包名JUnit 4和JUnit 5混用项目升级过程中最容易出现的情况是有人引入了JUnit Vintage引擎用于兼容JUnit 3/4用例同时代码里既有org.junit.TestJUnit 4又有org.junit.jupiter.api.TestJUnit 5。这种做法本身没问题因为两个引擎可以共存但它会带来一个小的困惑如果你在JUnit 5测试类里误用了JUnit 4的Test很多基于JUnit 5的断言和生命周期注解并不会生效测试可能会直接通过或失败但行为完全不符合你的预期。我的建议很简单统一用JUnit 5的注解。如果是旧项目迁移先把org.junit.Test全部替换为org.junit.jupiter.api.Test同时把Before改成BeforeEachAfter改成AfterEachBeforeClass改成BeforeAllAfterClass改成AfterAll。替换完跑一遍mvn test看还有没有编译问题。5.4 SpringBootTest是否必须单元测试和集成测试的边界如果是Spring Boot项目很多人会习惯性地在测试类上写SpringBootTest然后再写Test。对这个做法我一般会提醒SpringBootTest会启动完整的Spring应用上下文加载所有Bean、配置文件、数据源连接。在一个比较大的项目里这种测试跑一次可能就要十几秒甚至更久。如果你的测试只是验证一个纯Java工具类的逻辑完全没必要启动Spring上下文。正确的做法是区分场景纯Java逻辑工具类、算法、DTO、Validator等不要用SpringBootTest直接写普通Test就行运行飞快。需要依赖Spring容器的测试Service里的依赖注入、事务拦截等可以用SpringBootTest配合Autowired。Web层接口测试可以用SpringBootTest加AutoConfigureMockMvc用MockMvc的方式发HTTP请求不用真的起端口。这个边界如果不分清最直观的感受是跑整个测试类的时间从几秒变成几十秒日常调试的反馈速度会明显直线下降。5.5 方法之间互相“污染”测试的隔离性问题另一个高频坑是多个测试方法共享了同一个静态变量或同一个单例对象。比如public class OrderServiceTest { static ListString orders new ArrayList(); BeforeEach void setUp() { orders.add(order1); } Test void testOne() { orders.add(order2); assertEquals(2, orders.size()); } Test void testTwo() { assertEquals(2, orders.size()); } }因为orders是static的第一个测试方法跑完orders里增加了项目第二个测试方法一开始就是两个元素assertEquals(2, orders.size())理论上也许会过但真正的意图是把每个用例隔离到只包含自己的数据。如果你断然跑全类测试失败的概率很高。所以不要在测试方法之间共享可变的状态。每次BeforeEach创建全新的实例是最省心的方案。这也是JUnit要求每个测试方法创建新测试类实例的原因。如果是Spring的容器BeanBean默认是单例的多个测试方法之间如果通过Autowired拿到同一个BeanBean内部的可变字段也可能污染。比较实际的解法是先用Mockito把具有外部依赖的Bean Mock掉或者在自己的测试环境里准备好独立数据避免测试用例之间影响。6. 把Test用成一个提效工具快捷键、代码模板和经验补充说到快捷键IDEA里和测试相关的有两个我几乎天天用。第一个是CtrlShiftTMac上是CmdShiftT在某个类上按下它IDEA会弹出提示要么跳转到已有的测试类要么帮你新建一个测试类。新建的时候会弹出一个对话框让你勾选要生成哪些测试方法、用什么测试框架、方法前缀怎么命名非常方便。第二个是AltInsert在测试类里按它可以快速选择Generate Test方法生成。结合这两个快捷键写完业务类后顺手就补测试效率比手动建测试类再手动敲Test高很多。还有一个很实用的小技巧如果你不喜欢每次手动写Test方法里的框架代码可以在Settings里配置Live Template。比如你输入“tst”然后按Tab自动生成Test void test(){ }这样写测试时只需要敲一个触发词就能把骨架拉出来手速不快的人也能保持流畅。Live Template具体在Settings - Editor - Live Templates里配置把上面这个模板的缩写设为tst即可。另外补充一个我踩过的真实教训早期我把测试类命名成UserDaoTest还是UserDaoTests纠结了很久后来发现Maven的surefire默认扫描规则是包含Test开头的类名、以Test结尾的类名对Tests结尾的类虽然新版也会扫到但不同版本的行为不完全一致。为了保证行为一致我统一用XxxTest这种命名。这样不仅Maven扫得到IDEA里认起来也整齐。再强调一下日常开发的节奏写完一个方法先在脑子里想这个方法的边界情况有哪些然后写成测试用例马上跑。跑通了再继续往下写。这种“测试驱动”的模式虽然前期看着多花了几分钟但后期排查问题的时间会省回来一大截。身边不少同事从“补测试”变成“先测试”正是被这个节奏带来的反馈速度吸引的。这篇文章没有打算把Test的所有细节都一一罗列只把IDEA里用得上的配置和实战中容易踩的坑理了一遍。你在实际项目里如果遇到什么诡异的现象核心思路我都写在上面了先看依赖配没配齐再看目录标记对不对再确认代码里用的是JUnit 5还是JUnit 4的注解最后再检查数据隔离和运行配置。把这几个点过一遍绝大多数问题都能找到方向。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

frp内网穿透配置全解:从零到子域名实战与避坑指南 2026/10/1 13:44:39

frp内网穿透配置全解:从零到子域名实战与避坑指南

frp内网穿透配置一直是新手和老手都绕不开的一道坎,尤其是当你手上有一台公网服务器,却想让家里或办公室的内网服务能被外面访问时,frp基本是最省心的选择。这篇文章我会从零开始,完整演示frp服务端和客户端的配置全流程&#xff…

阅读更多 →
pygame小游戏源码包实战:环境配置、代码拆解与避坑指南 2026/10/1 13:44:39

pygame小游戏源码包实战:环境配置、代码拆解与避坑指南

简介:这是一套汇集二十个经典小游戏的 Python pygame 源码合集,所有游戏均亲测可正常运行,面向 Python 初学者、游戏开发入门者以及课堂教学场景,推荐使用 PyCharm 打开运行。游戏类型十分丰富,涵盖射击达人、动物对决…

阅读更多 →
只改两行配置,统一调度DeepSeek、Qwen与GLM的AI工作台 2026/10/1 13:44:39

只改两行配置,统一调度DeepSeek、Qwen与GLM的AI工作台

1. 为什么要把三个模型塞进同一个工作台我平时写代码、查资料、做技术方案,最烦的一件事就是来回切窗口。DeepSeek 用来做代码补全和逻辑推理,Qwen 用来处理长文档和中文理解,GLM 用来做快速问答和轻量任务,三个模型各有各的脾气&…

阅读更多 →
用WorkBuddy搭建自动AI日报系统:定时生成+微信推送全指南 2026/10/1 13:44:39

用WorkBuddy搭建自动AI日报系统:定时生成+微信推送全指南

如果你也是那种每天早上打开手机,被几十个公众号和新闻客户端轮番轰炸的人,那这篇文章应该正好能帮上忙。我最近干了一件特别“偷懒”的事:给 WorkBuddy 设了个闹钟,每天上午十点半,它自动把一份整理好的 AI 日报推进我…

阅读更多 →
用WorkBuddy打造每日自动推送的AI日报系统 2026/10/1 13:44:38

用WorkBuddy打造每日自动推送的AI日报系统

先交代一下背景。我是 WorkBuddy 的重度用户,平时写代码、整理技术资料、跑自动化脚本都靠它。用了几个月之后,我发现一个尴尬的地方:工具很聪明,但我每天还是要手动打开一堆网站去追 AI 圈的动态——今天哪个大模型发了新版本、哪…

阅读更多 →
Appium移动自动化测试从入门到实战:环境搭建、元素定位与脚本编写 2026/10/1 13:44:32

Appium移动自动化测试从入门到实战:环境搭建、元素定位与脚本编写

刚接触移动端自动化测试的时候,我绕了不小的弯路才真正把Appium用起来。这工具在业内的口碑很分裂:一方面它是移动应用自动化测试领域的“标配”,另一方面新手上路时,光是环境搭建和元素定位就能把热情消磨殆尽。今天这篇不整那些…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉