一、本文的采访

1. Pekka:水文的起因是什么?

小黑子:就是看到几个好为人 "师" 的评论ಠ_ಠ ,对 RF 与路由器之间的关系很好奇,想了解 RF 是路由器的唯一,还是只是备胎 ಥ ͡ ͜ʖ ͡ಥ

2. Pekka:说 RF 是过时的工具,我感应到有些人很激动,你分析下原因?

小黑子:分为两类人。

第一类是入行早的,在 robot Framework 上有大量的时间投资和经验,甚至还有相关著作的,在听到别人说它过时了,可能会感到自己的工作和技能被贬低。所以你可以看到,明明是在说工具过时,他们却一直在争辩技术没有过时一说。

第二类是新生代的测试,一般都是在第一份工作的老项目里有稍微接触过一点,他们肯定是体验过这个工具的不尽人意之处,也在后续其他公司看到了更好的模式和更好的工具,但是本着前大佬们选用这个工具,肯定是有他们不知道的缘由的自我 PUA 心理,形成了一种崇拜,对该工具的批评可能会被视为对自己所属群体或社区的批评,然后引发他们群体认同感的反应。

如同坤坤在上面 “鸡你太美”,下面的粉丝却如听仙乐耳暂明。

3. Pekka:传统企业真大多用的是 RF 吗?

小黑子: 这一行忘了一件事,早期 功能验证、自动化测试、性能测试 是三个岗位,那就造成自动化测试工程师选用测试工具时,得考虑非编程背景的功能测试人员,在那个时候,RF 无疑是最好的选择。像路由器测试这种岗位,招功能测试的要求侧重点是懂网络协议,招自动化测试侧重点是测试工具使用和基础编程能力,得益于 RF 的工具特性,这帮自动化的工作内容是天天在排错、维护用例、解决灵活性不足的问题🤣。且这种企业的版本迭代速度不快,公司出生得早又死得慢,所以很多自动化项目一直沿用下来,新人不敢乱改,老人需要吃老本,所以 RF 在这类企业中存活下来。

4. Pekka:你用过 RF 吗?

小黑子: 刚入行时用过,感觉不好用后也几乎没去深入学过。这里放两个用例可以自行体会下,新生代的测试应该 没有人会想不开 去选用 RF 作为落地自动化的工具吧,还有 RF 记得注意空格🤣

用例是:搜索 “robot framework”,然后在睡眠 5 秒后关闭浏览器

*** Settings ***
Library    SeleniumLibrary

*** Variables ***
${URL}    https://www.baidu.com
${SEARCH_TERM}    robot framework
${IMPLICIT_WAIT}    10

*** Test Cases ***
打开百度搜索
    Open Browser    ${URL}    chrome
    Set Selenium Implicit Wait    ${IMPLICIT_WAIT}
    Input Text    id=kw    ${SEARCH_TERM}
    Click Button    id=su
    Sleep    5
    Close Browser

import time
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
import logging

# 配置日志,仅记录错误级别及以上的日志
logging.basicConfig(level=logging.ERROR)
logger = logging.getLogger(__name__)

@pytest.fixture(scope="function")
def browser():
    # 初始化浏览器
    driver = webdriver.Chrome()  # ChromeDriver路径
    yield driver
    # 关闭浏览器
    driver.quit()

def wait_for_element(driver, by, value, timeout=10):
    """等待元素出现并返回元素对象"""
    try:
        element = WebDriverWait(driver, timeout).until(
            EC.presence_of_element_located((by, value))
        )
        return element
    except TimeoutException:
        logger.error(f"元素 {value}{timeout} 秒内未加载完成")
        raise

def test_baidu_search(browser):
    url = 'https://www.baidu.com'
    search_term = 'robot framework'
    search_box_id = 'kw'
    search_button_id = 'su'

    # 打开百度首页
    browser.get(url)

    # 等待搜索框加载并出现
    search_box = wait_for_element(browser, By.ID, search_box_id)

    # 在搜索框中输入搜索词
    search_box.send_keys(search_term)

    # 等待搜索按钮加载并出现
    search_button = wait_for_element(browser, By.ID, search_button_id)

    # 点击搜索按钮
    search_button.click()

    # 睡眠5秒
    time.sleep(5)

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

5. Pekka:那你觉得 RF 没有使用价值了吗?

小黑子: 我保留意见,反正我不用🤣,这种问题没有答案,总有人会试图证明一个不好用的工具好用在哪里。我趋利避害,哪个更好用就用哪个,不好用的那个就是过时

6. Pekka:我看原话是 “交换机、防火墙、路由器等硬件设备”,你怎么只提路由器?

小黑子:以复杂度来说,路由器比防火墙和交换机更复杂 。以自动化需求来说,路由器和防火墙通常更频繁地需要自动化。但这里的防火墙指的是企业级的防火墙设备,所以选用了较为常见的路由器🤣

7. Pekka:你测试过路由器?

小黑子:完全没有,但测试一个新的项目只需要做到知道 ‘测啥’ 和 ‘咋测’ 就可以开展测试,这里可以查查资料了解🤣:

8. Pekka:那路由器的自动化只能用 RF 完成吗?

小黑子:其实这点我也蛮奇怪的,为什么有人会有这个想法?🤣,甚至还拿它做为 RF 不过时的证据🤣。

综上所述,路由器的自动化跟 RF 完全就不是什么绑定的关系,任何一个能支持大量第三方库的测试工具都能做路由器的自动化🤣

9. Pekka:真的吗? 那你用 pytest 写写看?

小黑子: 首先准备测试环境
用华为的 ensp 仿真,搭一个最简单的网络 cloud+ 路由器,虚机里的路由器跟我在同一个网段,我就能在本地电脑远程访问和配置

路由器设置指令

###配置路由器
sys
sysname AR3260
interface GigabitEthernet0/0/0
ip address 192.168.5.66 255.255.255.0
quit

###配置AAA模式和ssh用户信息
aaa
local-user admin password cipher Huawei@123
local-user admin privilege level 15
local-user admin service-type ssh
quit

### 启用VTY接口上的SSH服务
user-interface vty 0 4
authentication-mode aaa
protocol inbound ssh
quit

###启用 SSH 服务,并配置相关参数。
ssh user admin authentication-type password
stelnet server enable

save

一、功能类用例:主要是配置类或者一些日常巡检指令,具体的方式是通过 SSH 登录路由器,发送路由器指令进行配置操作
这里写个 demo

import paramiko
import time 
import pytest 

# 配置信息:路由器
hostName = '192.168.5.66'
port = 22
userName = 'admin'
passWord = 'Huawei@123'


@pytest.fixture(scope='module')
def ssh_client():
    #创建SSH客户端
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    try:
      # look_for_keys参数需要设置为False,以防止程序自动搜索和添加SSH密钥,然后一直连接不上
      client.connect(hostName, port, userName, passWord,look_for_keys=False)
      ssh_shell = client.invoke_shell()
      yield ssh_shell,client
    finally:
      # 关闭SSH连接
      client.close()

def execute_command(ssh_shell, command, delay=1):
    ssh_shell.send(command + '\n')
    time.sleep(delay)
    output = ''
    while ssh_shell.recv_ready():
        output += ssh_shell.recv(65535).decode('utf-8')
    return output

# 1 . 检查设备版本
def test_check_device_version(ssh_client):
    ssh_shell, client = ssh_client
    command = 'display version'
    output = execute_command(ssh_shell, command)
    assert 'Huawei AR3260' in output, "设备版本检查失败"

 #  2 . 检查网络
def test_ping_to_internet(ssh_client):
  ssh_shell,client = ssh_client
  command = "ping -c 1 8.8.8.8"
  output = execute_command(ssh_shell,command)
  assert "ttl" in output.lower(), f"{command}测试失败"

# 3. 检查IP配置
def test_check_ip_config(ssh_client):
    ssh_shell, client = ssh_client
    command = 'display ip interface brief'
    output = execute_command(ssh_shell, command)
    assert '192.168.5.66/24' in output, "IP配置异常"


if __name__ == "__main__":
    pytest.main(["-vs", __file__])

这里截图证明下,真的可以访问的,没有骗各位🤣


二、检查 WiFi 性能也是没问题的,借助 ipref3,自己根据需要添加场景和加入到 pytest 里

import subprocess
import json
import time

def run_iperf3(server, port=5201):
    command = [r'D:\ipref3\iperf3.exe', '-c', server, '-p', str(port), '-J']
    try:
        start_time = time.time() 
        result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
        end_time = time.time()  # 记录结束时间
        output = result.stdout.decode('utf-8')
        json_output = json.loads(output)
        return json_output, start_time, end_time
    except subprocess.CalledProcessError as e:
        print(f"指令 '{e.cmd}' 退出状态 {e.returncode}.")
        print(f"stderr: {e.stderr.decode('utf-8')}")
        return None

# demo
server_ip = "192.168.5.47"  # 替换为实际的服务器 IP 地址
result, start_time, end_time = run_iperf3(server_ip)
if result:
    # 
    start_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))
    end_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time))
  # 计算平均带宽,并保留小数点后两位
    avg_bandwidth = round(result.get('end', {}).get('sum_received', {}).get('bits_per_second', 0) / 1e6, 2)

    print(f"测试开始时间: {start_timestamp}")
    print(f"平均带宽: {avg_bandwidth} Mbps")
    print(f"测试结束时间: {end_timestamp}")
else:
    print("iperf3 测试失败。")

运行结果

服务端

三、模拟 DHCP 请求拿 IP 地址

from scapy.all import *


client_mac1 = RandMAC()
ifaces = 'Realtek PCIe GbE Family Controller'

# 定义一个函数来发送DHCP Discover消息
def send_dhcp_discover():
    # 创建DHCP Discover消息
    print("发送 DHCP Discover 信息...")
    xid_random=random.randint(1,999999999)
    dhcp_discover = Ether(src=client_mac1,dst="ff:ff:ff:ff:ff:ff") / \
                    IP(src="0.0.0.0", dst="255.255.255.255") / \
                    UDP(dport=67,sport=68) / \
                    BOOTP(xid = xid_random ,chaddr=mac2str(client_mac1)) / \
                    DHCP(options=[("message-type", "discover"), "end"])

    # 发送DHCP Discover消息

    sendp(dhcp_discover,iface=ifaces)
def send_dhcp_request(client_mac, server_ip,client_chaddr,client_xid,client_yiaddr):
    print("发送 DHCP Request...")
    dhcp_request = Ether(src=client_mac,dst="ff:ff:ff:ff:ff:ff") / \
                   IP(src="0.0.0.0", dst="255.255.255.255") / \
                   UDP(sport=68, dport=67) / \
                   BOOTP(chaddr=client_chaddr, xid=client_xid) / \
                   DHCP(options=[("message-type", "request"), ("server_id", server_ip), ("requested_addr", client_yiaddr), "end"])
    print(f'物理地址{client_mac},申请到的IP{client_yiaddr}')
    # 发送DHCP Request消息
    sendp(dhcp_request, verbose=1,iface=ifaces)

def demo(pkt):
    if pkt["DHCP options"].options[0][1] == 2:
        print("收到DHCP Offer")
        print(pkt[DHCP].options[1][1])
        send_dhcp_request(pkt[Ether].dst,pkt[DHCP].options[1][1],pkt[BOOTP].chaddr, pkt[BOOTP].xid,pkt[BOOTP].yiaddr)
        print("正在分配ip%s" %(pkt[BOOTP].yiaddr))
        if pkt[DHCP].options[0][1]==5:
            print("已经分配ip%s" %(pkt[BOOTP].yiaddr))

send_dhcp_discover()
data = sniff(filter="udp and (port 67 or 68)", count=5,prn=demo,iface='网卡名')

抓包证明下🤣

10. Pekka:你觉得培训机构怎样?

小黑子:
培训机构并非贬义的代名词,早期互联网资料不足时,很多工友都是通过培训机构入的行。但是在 gpt 的时代,其实学什么东西都可以让 AI 进行辅助了。像入门路由器的测试,用 网络资料 +TCP/IP +chatgpt 足以🤣

11. Pekka:你怎么看 “没有过时的技术,只有过时的人”?

小黑子:除了利益是永不过时,其他都是屁🤣。市场的一切选择都是利润二字,不能直接创造经济价值的岗位就更别提自己个体的所谓实力了,应该照照镜子,问下自己是不是有目前风口业务的经验 还有 年不年轻

12. Pekka:你写这个的目的是?

小黑子: 主要是学习下怎么给路由器写自动化,同时不爽 一小部分 通过身份和经验施压新人,打压质疑的现象。人设总是谦虚向上,实际嗅到一丁点质疑,就表现出强烈的反感和抵触,典型的当婊子还想立牌坊🤣

13. Pekka:你这样说,是不是太伤他们了?

小黑子:



↙↙↙阅读原文可查看相关链接,并与作者交流