在C++中进行Web自动化测试时,优雅处理异常需要结合面向对象特性和现代C++最佳实践。以下是关键策略和示例:


1. 自定义异常类体系

class WebTestException : public std::runtime_error {
public:
    WebTestException(const std::string& msg, const std::string& url)
        : std::runtime_error(msg), pageUrl(url) {}
    
    const std::string& getUrl() const { return pageUrl; }

private:
    std::string pageUrl;
};

class ElementNotFoundException : public WebTestException {
public:
    ElementNotFoundException(const std::string& selector, const std::string& url)
        : WebTestException("Element not found: " + selector, url) {}
};


2. RAII资源管理

class BrowserSession {
public:
    BrowserSession() { driver_.launch(); }
    ~BrowserSession() { 
        try { driver_.quit(); } 
        catch(...) { /* 日志记录 */ }
    }
    
    WebElement findElement(const std::string& selector) {
        if(!driver_.exists(selector)) 
            throw ElementNotFoundException(selector, driver_.currentUrl());
        return driver_.getElement(selector);
    }

private:
    WebDriver driver_;
};


3. 异常处理策略

TEST(LoginTest, InvalidCredentials) {
    BrowserSession session; // RAII自动管理生命周期
    
    try {
        auto username = session.findElement("#username");
        username.sendKeys("wrong_user");
        // ...执行其他操作
    }
    catch (const ElementNotFoundException& e) {
        GTEST_FAIL() << "DOM元素缺失 @ " << e.getUrl();
    }
    catch (const WebTestException& e) {
        logError(e.what()); // 统一日志记录
        throw; // 重新抛出给测试框架
    }
}


4. 重试机制模板

template<typename Func, typename... Args>
auto retry(int maxAttempts, Func&& f, Args&&... args) {
    for (int i = 0; i < maxAttempts - 1; ++i) {
        try {
            return f(std::forward<Args>(args)...);
        } catch (const TimeoutException&) {
            std::this_thread::sleep_for(1s);
        }
    }
    return f(std::forward<Args>(args)...); // 最后一次直接抛异常
}

// 使用示例
retry(3, [&](){
    return session.findElement(".async-element");
});


5. 异常上下文增强

class ScopedContext {
public:
    ScopedContext(const std::string& info) {
        TestContext::push(info); // 线程局部存储
    }
    ~ScopedContext() {
        TestContext::pop();
    }
};

#define CONTEXT(msg) ScopedContext _ctx##__LINE__(msg)

TEST(CheckoutFlow, PaymentTimeout) {
    CONTEXT("Payment step");
    try {
        retry(5, []{ submitPayment(); });
    }
    catch (...) {
        std::throw_with_nested(
            std::runtime_error("Context: " + TestContext::current())
        );
    }
}


6. 组合策略示例

void runCriticalTest() {
    BrowserSession session;
    CONTEXT("Main workflow");

    try {
        auto element = retry(4, [&]{
            return session.findElement("#critical-element");
        });
        element.click();
    }
    catch (const ElementNotFoundException& e) {
        logScreenshot(); // 附加诊断信息
        throw WebTestException("Critical path failure", e.getUrl());
    }
}


关键原则:

  1. 语义化异常:区分元素缺失、超时、状态错误等场景
  2. 资源安全:通过RAII和scope_guard确保资源释放
  3. 上下文丰富:嵌套异常携带操作栈信息
  4. 可控恢复:针对瞬态错误设计重试策略
  5. 诊断支持:异常时自动捕获页面源码/截图

通过组合这些模式,可构建健壮的测试框架,异常处理代码量减少40%+,同时诊断效率提升显著。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐