AI人工智能与软件测试

完全免费!如何安装openclaw

这几天clawdbot的改名风波闹的沸沸扬扬。

从clawdbot到moltbot再到openclaw,一周装了我3个版本,搞得我都有点精神分裂了。

两个月前,clawdbot的作者peter花了一个周末搞了个叫“WhatsApp Relay”的小项目,结果现在GitHub星标破10万,一周内吸引了200万访问者。完全超出预期。

今天peter正式宣布:这个项目改名叫OpenClaw。

这个名字一路走来挺戏剧:最早叫Clawd,2025年11月诞生,就是那个大模型“Claude”加个爪子的梗,这是英文的谐音梗,我也不太懂,反正logo倒是挺可爱的。

结果火了之后,claude母公司的法务礼貌敲门了,这个名字太像了,蹭了我们的流量,能不能改?

peter表示:我们懂,向资本低头,马上整改。

然后凌晨5点在Discord脑暴,选了Moltbot的名字。molt大概是龙虾要长大就得蜕壳的意思,象征成长。很有诗意,但读起来总有点拗口。

peter不满意,几番折腾之后,现在终于定下来一个新名字:OpenClaw。

这次peter学乖了,商标没有被注册、域名也买好了、代码也迁移了。

现在的名字我觉得是很贴切的:Open代表开源、开放、社区驱动

Claw:就是爪子,保留龙虾爪子的血统,向起点致敬。


这次应该不会再改名字了,终于可以给大家分享一下如何安装openclaw了,对于没有技术基础的同学来说,本地安装还是很有难度的。

下面给大家演示一下如何在mac和linux上安装openclaw,这里我们的目标是让国内的同学不花一分钱把服务运行起来。

YouTube视频

B站视频

mac 系统

先看mac系统。

首先安装nodejs的最新稳定版本。我安装的是24.13.0,推荐用nvm安装,我把命令放这里了。

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
nvm install --lts

Mac上还需要安装 Command Line Tools,命令放在下面了。

# 先彻底删除旧的(很重要,很多时候不删它就装错版本)
sudo rm -rf /Library/Developer/CommandLineTools

# 让系统重新拉取(会弹出安装窗口,按提示点继续)
sudo xcode-select --install

安装git,我们用brew安装。

brew install git

接下来把官网上的命令拷贝下来,在命令行里执行。

测试周刊006: playwrightv1.53的新功能

在一个已有开发节奏的团队中,作为第一位测试人员去推行新流程,绝非易事。

你会被开发质疑:是不是要拖慢上线进度?是不是要卡死流程,让整个开发团队都不爽?

这些成见不是你的错,但你必须面对它们。

pydoll 初体验

之前介绍过一款新的 ui 自动化测试工具—-pydoll

今天抽空在 github 的 copilot 的帮助下试用了一下。

我用 pydoll 实现了一个测试任务列表的测试套件,包含 5 个测试用例。

具体用例如下

import asyncio
import os
import unittest
from pydoll.browser.chromium import Chrome
from pydoll.browser.options import ChromiumOptions
from pydoll.constants import Key

class TestTodoMVC(unittest.IsolatedAsyncioTestCase):
    async def asyncSetUp(self):
        options = ChromiumOptions()
        options.add_argument('--start-maximized')
        options.add_argument('--disable-notifications')
        self.browser = Chrome(options=options)
        self.tab = await self.browser.start()
        await self.tab.go_to('https://todomvc.com/examples/react/dist/')

    async def asyncTearDown(self):
        await self.browser.__aexit__(None, None, None)

    async def test_add_todo(self):
        new_todo = await self.tab.find(class_name='new-todo', timeout=5, raise_exc=True)
        await new_todo.type_text("Install pydoll")
        await asyncio.sleep(1)
        await new_todo.press_keyboard_key(Key.ENTER)
        todo_items = await self.tab.find(class_name = 'view', timeout=5, find_all=True, raise_exc=True)
        found = False
        texts = []
        for item in todo_items:
            text = await item.text
            texts.append(text)
            if "Install pydoll" in text:
                found = True
                break
        self.assertTrue(found)

    async def test_complete_todo(self):
        await self.test_add_todo()
        toggle = await self.tab.find(class_name="toggle", timeout=5, raise_exc=True)
        await toggle.click()
        completed = await self.tab.find(class_name='completed', timeout=5, raise_exc=True)
        self.assertIsNotNone(completed)

    async def test_delete_todo(self):
        await self.test_add_todo()
        todo_item = await self.tab.find(class_name='view', timeout=5, raise_exc=True)
        await todo_item.click()
        destroy_btn = await todo_item.find(class_name='destroy', timeout=5, raise_exc=True)
        await destroy_btn.click()
        todo_items = await self.tab.find(class_name='view', find_all=True)
        found = False
        for item in todo_items:
            if "Install pydoll" in item.text:
                found = True
                break
        self.assertFalse(found)

    async def test_filter_todo(self):
        await self.test_add_todo()
        toggle = await self.tab.find(class_name="toggle", timeout=5, raise_exc=True)
        await toggle.click()
        active_filter = await self.tab.find(text="Active", timeout=5, raise_exc=True)
        await active_filter.click()
        await asyncio.sleep(1)
        active_items = [item for item in await self.tab.find(class_name = 'view', find_all=True)]
        self.assertEqual(len(active_items), 0)
        completed_filter = await self.tab.find(text="Completed", timeout=5, raise_exc=True)
        await completed_filter.click()
        await asyncio.sleep(1)
        completed_items = await self.tab.find(class_name = 'view', find_all=True)
        found = False
        for item in completed_items:
            title = await item.text
            if "Install pydoll" in title:
                found = True
                break
        self.assertTrue(found)

    async def test_screenshot(self):
        await self.test_add_todo()
        screenshot_path = os.path.join(os.getcwd(), 'pydoll_repo.png')
        await self.tab.take_screenshot(path=screenshot_path)
        self.assertTrue(os.path.exists(screenshot_path))

if __name__ == "__main__":
    unittest.main()

上面的代码实现了

测试周刊005: Google是怎么做测试的

在 Google 早期,测试并不是首要任务。公司文化高度依赖工程师的才华——聪明的人写聪明的代码。大多数情况下,这种方式都很有效。少数系统部署了集成测试,但广泛的、结构化的测试极其罕见。这就像软件开发的"狂野西部"时代。

测试周刊004: 单元测试和接口测试用例将成为标配

马上就到端午假期了。

今天在电梯听到两位女士的对话,大概的意思是一位认为只有一天的假期有点不太过瘾,而另一位觉得假期归来以后上 4 休 2 已经是非常划算了。

反正我是同意后者的。

https://images.unsplash.com/photo-1749984340771-c3a967db0a28?q=80&w=2066&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D

观点

AI 将使得单元测试和接口测试成为标配

前些天 deepseek 发布了新模型,该模型在代码能力上有了较大的提升。

有人尝试之后表示模型不仅可以正确实现编码需求,还可以在生成代码的同时给出完整的单元测试用例。

今后将有越来越多的代码会由 ai 实现,而我们可以非常自信的要求 ai 在给出实现的同时,给出完成的单元测试用例和接口测试用例。

因此在不久的将来,单元测试用例和接口测试用例将会成为增量代码的标配了吧。

测试同学可能不需要人人都会写单元测试用例了,但是学会看懂测试用例,并用测试思维来对用例进行评审,反而是更实用的技能了。

从质量保证到集成保证

https://medium.com/@sean.zhang/lets-rethink-the-role-of-qa-it-s-not-about-owning-quality-ed159d0a424b

传统的"质量保证"概念存在两个极端问题:

  • 过度依赖 QA:认为 QA 团队独自负责产品质量,其他团队可以推卸责任
  • 完全取消 QA:认为每个工程师都应该"拥有质量",但缺乏系统级验证

作者认为传统的"质量保证"(QA)概念存在误导性,因为质量应该是每个团队的共同责任,而不是 QA 部门的专属职责。

他提出将 QA 重新定义为"集成保证"(Integration Assurance),专注于验证现代软件系统中多个服务和组件之间的协同工作,就像苹果公司需要确保 iPhone 各个供应商的零件能完美集成一样。

这个角色类似足球比赛中的守门员——不是唯一的防线,但是防止问题到达用户的最后屏障,同时帮助发现系统级的协调问题和集成风险,而 AI 测试工具应该主要由这个集成保证团队来使用,以确保从全局视角进行有效的端到端验证。

自动化测试

有效的软件测试需要通过测试替身(Test Doubles)来隔离被测系统,从而编写可控、可靠的单元测试

https://medium.com/@raissa.puti/behind-the-green-check-a-guide-to-test-doubles-7199be3b08c2

作者认为,真正的测试不仅仅是检查功能是否正常运行,而是要通过 Dummy、Stub、Spy、Mock、Fake 等不同类型的测试替身来替代真实的外部依赖(如 API、数据库、时间服务等),这样可以:

  • 控制测试环境和输入数据,
  • 验证特定的交互行为,
  • 避免依赖不稳定的外部服务
  • 提高测试速度和可靠性。

作者以自己的 React 项目 SiNgawas 为例,展示了如何在前端测试中应用这些概念,同时分享了借助 AI 工具来改进测试设计的经验。文章强调,好的测试应该专注于验证有意义的行为,而不是简单地检查 UI 渲染,通过合理使用测试替身可以让每个测试都有明确的目的和可预测的结果。