专栏文章 python 学习 使用重试模式来提升自动化测试的稳定性

大话性能 · 2023年07月25日 · 最后由 Mr.Shuo 回复于 2023年08月01日 · 5079 次阅读

自动化测试,特别是 ui 自动化的稳定性提升是非常困难的,出错了就重试这个简单的策略可以帮助我们处理一些难以预料的异常情景,从而提升测试的整体稳定性。
更多内容可以学习《测试工程师 Python 工具开发实战》书籍《大话性能测试 JMeter 实战》书籍

这篇文章就分享了几种重试的设计模式,通俗易懂而且相当实用。

1、动态重试

async function dynamicRetry(actions, maxRetries) {
    let retryCount = 0;

    async function retryAction() {
        try {
            return await actions();
        } catch (error) {
            if (retryCount < maxRetries) {
                retryCount++;
                return retryAction();
            } else {
                throw error;
            }
        }
    }
    return await retryAction();
}


it("Testing the dynamic retry pattern", async () => {
    await demoPage.navigateToDemoPageTextBoxes();
    await browser.pause(1000);
    await dynamicRetry(async () => {
        await demoPage.fillFullName("John Doe");
        await demoPage.fillEmail("test@gmail.com");
        await demoPage.fillCurrentAddress("test address");
        await demoPage.clickFakeButton();
    }, 3);
});

该模式的核心是设置一个最大的重试次数,每次重试过后次数加一,直到达到阈值。

2、轮询重试

另一种常见的重试模式是使用超时和轮询。这种方法会重复检查一组操作是否成功完成或者是否达到了超时时间。

async function pollRetry(actions, timeout, pollInterval) {
    const startTime = Date.now();
    let lastError;

    while (Date.now() - startTime < timeout) {
        try {
            await actions();
            return;
        } catch (error) {
            lastError = error;
            await sleep(pollInterval);
        }
    }

    throw lastError;
}

function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}


it("Testing the poll retry pattern", async () => {
    await demoPage.navigateToDemoPageTextBoxes();
    await browser.pause(1000);
    await pollRetry(
        async () => {
            await demoPage.fillFullName("John Doe");
            await demoPage.fillEmail("test@gmail.com");
            await demoPage.fillCurrentAddress("test address");
            await demoPage.clickFakeButton();
        },
        20000,
        5000
    );
});

这个模式的核心是设置一个总的超时时间,如果在这个时间段内发生了异常,那么就每隔一段时间重试一下。

selenium 的 wait unitl 接口就是这种重试模式。

3、异常重试

这是最常见的一种重试方式,好处是可以针对不同的异常执行不同的重试策略。

function errorHandlingRetry(actions) {
    return new Promise(async (resolve, reject) => {
        try {
            await actions();
            resolve();
        } catch (error) {
            if (error instanceof ElementNotFoundError) {
                // Handle the case when the element is not found
       console.error("Element not found:", error.elementSelector);
       await sleep(1000);
       await actions();
            } else if (error instanceof TimeoutError) {
                // Handle the case when a timeout occurs
       console.error("Timeout occurred:", error.message);
       await sleep(500);
       await actions();
            } else {
                // Handle other types of errors
    console.error("An error occurred:", error);
            }
            reject(error);
        }
    });
}

it("Testing the error handling retry pattern", async () => {
    await demoPage.navigateToDemoPageTextBoxes();
    await browser.pause(1000);
    await errorHandlingRetry(async () => {
        await demoPage.fillFullName("John Doe");
        await demoPage.fillEmail("test@gmail.com");
        await demoPage.fillCurrentAddress("test address");
        await demoPage.clickFakeButton();
    });
});

4、指数退避

指数退避是一种重试策略,其中每次尝试之间的间隔呈指数递增。这种方法有助于减轻拥塞并减少对系统的负载。以下是一个示例实现:

async function retryWithExponentialBackoff(actions, maxRetries, initialDelay) {
    let retryCount = 0;
    let delay = initialDelay;

    while (retryCount < maxRetries) {
        try {
            await actions();
            return;
        } catch (error) {
            console.error("Error:", error);
        }
        await sleep(delay);
        delay *= 2;
        retryCount++;
    }
    throw new Error(
        "Retry limit exceeded: Actions did not complete successfully."
    );
}


it("Testing the retry with exponential backoff pattern", async () => {
    await demoPage.navigateToDemoPageTextBoxes();
    await browser.pause(1000);
    await retryWithExponentialBackoff(
        async () => {
            await demoPage.fillFullName("John Doe");
            await demoPage.fillEmail("test@gmail.com");
            await demoPage.fillCurrentAddress("test address");
            await demoPage.clickFakeButton();
        },
        4,
        1000
    );
});

其实这种方式也是设置一个最大的重试次数,不过因为增加了指数退让的关系,所以每次重试的间隔都会变长,避免短时间反复重试给被测系统造成巨大压力。

5、随机间隔重试

随机间隔为重试机制增加了随机因素,可以帮助避免执行中的同步问题和模式。其实就是每次重试等待的时间是是随机的。

async function retryWithRandomizedInterval(
    actions,
    maxRetries,
    minDelay,
    maxDelay
) {
    let retryCount = 0;

    while (retryCount < maxRetries) {
        try {
            await actions();
            return;
        } catch (error) {
            console.error("Error:", error);
        }
        const delay = Math.floor(
            Math.random() * (maxDelay - minDelay + 1) + minDelay
        );
        await sleep(delay);
        retryCount++;
    }
    throw new Error(
        "Retry limit exceeded: Actions did not complete successfully."
    );
}


it("Testing the retry with a randomized interval pattern", async () => {
    await demoPage.navigateToDemoPageTextBoxes();
    await browser.pause(1000);
    await retryWithRandomizedInterval(
        async () => {
            await demoPage.fillFullName("John Doe");
            await demoPage.fillEmail("test@gmail.com");
            await demoPage.fillCurrentAddress("test address");
            await demoPage.clickFakeButton();
        },
        3,
        1000,
        3000
    );
});

总结

记住下面几种重试模式
动态重试
异常重试
轮询重试
指数退避

更多内容可以学习《测试工程师 Python 工具开发实战》书籍《大话性能测试 JMeter 实战》书籍

共收到 3 条回复 时间 点赞

python 教程为什么用 js

协成这个东西这么不好理解,需要一定水平才用得了,另外一般测试脚本用得着协成异步 ?(性能可能需要,并发加状态切换)
重试这个东西,直接一个装饰器就解决了。

pytest 的 rerun-failure 就可以了啊

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册