自動化測試平臺方案可行性探索

1.需求分析

隨著產(chǎn)品規(guī)模不斷完善,功能模塊逐漸增加,傳統(tǒng)的人工測試逐步變得低效。為了提高測試效率,可以將簡單的功能測試點(diǎn)交由自動化執(zhí)行,讓測試人員可以空出更多的時間去關(guān)注業(yè)務(wù),流程。而傳統(tǒng)的自動化測試腳本由于維護(hù)性差,成本高,收益低等因素導(dǎo)致難以有效的推行。而測試平臺化規(guī)劃好的話能將業(yè)務(wù)與代碼的耦合度降低,有利于后期維護(hù)與可持續(xù)集成。

2.方案設(shè)想

所有數(shù)據(jù)均保存在數(shù)據(jù)庫中,提供Web頁面進(jìn)行操作,其中

1.頁面數(shù)據(jù):源自PageObject設(shè)計(jì)模式,具體表現(xiàn)形式為一個頁面一項(xiàng)數(shù)據(jù),以米多來發(fā)管理后臺登錄頁為例:

2.自定義方法:平臺提供瀏覽器基礎(chǔ)操作并提供功能用以保存測試人員自定義的方法,例如:

平臺提供基礎(chǔ)的點(diǎn)擊元素以及向元素輸入信息基礎(chǔ)功能。結(jié)合頁面數(shù)據(jù)保存登錄頁的自定義方法向用戶名輸入框中輸入用戶名,向密碼輸入框中輸入密碼,向驗(yàn)證碼輸入框中輸入驗(yàn)證碼,點(diǎn)擊登錄按鈕等。后續(xù)通過關(guān)鍵字驅(qū)動進(jìn)行調(diào)用。

3.自定義類方法:自定義方法并不能解決所有的需求,有些復(fù)雜的邏輯時,上述的方式并不適用,所以需要通過類中實(shí)現(xiàn)邏輯方法并提供給外界調(diào)用。例如需求:在一個table中需要通過判斷某元素的內(nèi)容,符合預(yù)期后再進(jìn)行操作

以上三種結(jié)合起來生成測試用例。并與測試數(shù)據(jù)形成測試用例集(關(guān)鍵字驅(qū)動以及數(shù)據(jù)驅(qū)動相結(jié)合的混合驅(qū)動模式)再通過所選用配置最終形成自動化執(zhí)行的測試腳本。(配置:解決測試用例運(yùn)行環(huán)境,瀏覽器等相關(guān)問題)然后交給執(zhí)行引擎執(zhí)行并且輸出測試報(bào)告

3.核心代碼

1.基礎(chǔ)父類

/**
 * 基礎(chǔ)父類,所有PageObject類均繼承該類
 * 
 * @author miduo
 *
 */
public class Page {
    private WebDriver driver;

    public Page(WebDriver driver) {
        super();
        this.driver = driver;
        if (this.driver != null) {
            this.driver.manage().window().maximize();
        }
    }

    public WebDriver getDriver() {
        return driver;
    }

    @Auto(key = "click")
    public void click(String locator) {
        findElement(locator).click();
    }

    @Auto(key = "input")
    public void input(String locator, String value) {
        findElement(locator).sendKeys(value);
    }

    @Auto(key = "open")
    public void open(String url) {
        driver.get(url);
    }

    /**
     * 通過反射獲取類自定義方法
     * 
     * @param key
     * @return
     */
    protected Method getCustomMethodByKey(String key) {
        Method[] methods = getClass().getMethods();
        for (Method method : methods) {
            Auto autoKey = method.getAnnotation(Auto.class);
            if (autoKey != null && autoKey.key().equals(key)) {
                return method;
            }
        }
        return null;
    }

    protected final WebElement findElement(String locator) {
        int index = locator.indexOf(".");
        String type = locator.substring(0, index).toLowerCase();
        String value = locator.substring(index + 1);
        switch (type) {
        case "id":
            return findElement(By.id(value));
        case "name":
            return findElement(By.name(value));
        case "css":
            return findElement(By.cssSelector(value));
        case "xpath":
            return findElement(By.xpath(value));
        case "class":
            return findElement(By.className(value));
        case "tag":
            return findElement(By.tagName(value));
        case "link":
            return findElement(By.partialLinkText(value));
        default:
            return null;
        }
    }

    private final WebElement findElement(By by) {
        return new WebDriverWait(driver, 10).until(new ExpectedCondition<WebElement>() {
            @Override
            public WebElement apply(WebDriver d) {
                return d.findElement(by);
            }
        });
    }
}

2.PageObject具體實(shí)現(xiàn)類

public class LoginPage extends Page {

    public LoginPage(WebDriver driver) {
        super(driver);
    }

    /**
     * PageObject自定義類方法:登錄
     * 
     * @param userName
     * @param password
     * @param captcha
     */
    @Auto(key = "login")
    public void login(String userName, String password, String captcha) {
        input("id.Account", userName);
        input("id.Password", password);
        input("id.Captcha", captcha);
        click("xpath.//input[@type='submit']");
    }
}

3.自定義方法

public class Step {
    private Class<? extends Page> clazz;
    private String methodKey;
    private Object value;

    public Step() {
        super();
    }

    public Step(Class<? extends Page> clazz, String methodKey, Object value) {
        super();
        this.clazz = clazz == null ? Page.class : clazz;
        this.methodKey = methodKey;
        this.value = value;
    }

    public Class<? extends Page> getClazz() {
        return clazz;
    }

    public void setClazz(Class<? extends Page> clazz) {
        this.clazz = clazz;
    }

    public String getMethodKey() {
        return methodKey;
    }

    public void setMethodKey(String methodKey) {
        this.methodKey = methodKey;
    }

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }
}

4.測試用例以及測試數(shù)據(jù)

public class TestCase {

    private ArrayList<Step> steps;

    public TestCase() {
        super();
        this.steps = new ArrayList<>();
    }

    public ArrayList<Step> getSteps() {
        return steps;
    }

    public void setSteps(ArrayList<Step> steps) {
        this.steps = steps;
    }

    public void addStep(Step step) {
        this.steps.add(step);
    }

    public Result perform(WebDriver driver, Parameter parameter) {
        Result result = new Result();
        for (Step step : steps) {
            Object[] value = step.getValue();
            Object[] coValue = new Object[value.length];
            Boolean change= false;
            if (parameter != null) {
                for (int i = 0; i < value.length; i++) {
                    String key = value[i].toString();
                    coValue[i] = key;
                    if (key.startsWith("${") && key.endsWith("}")) {
                        change= true;
                        Object v = parameter.get(key.substring(2, key.length() - 1));
                        value[i] = v == null ? value[i] : v;
                    }
                }
            }
            if (!step.perform(driver, value)) {
                result.setResult(false);
                return result;
            }
            if (change) {
                step.setValue(coValue);
            }
        }
        result.setResult(true);
        return result;
    }
}

public class Parameter {
    private Map<String, Object> parameter;

    public Parameter() {
        super();
        this.parameter = new HashMap<>();
    }

    public void add(String key, Object value) {
        this.parameter.put(key, value);
    }

    public void remove(String key) {
        this.parameter.remove(key);
    }

    public Object get(String key) {
        return this.parameter.get(key);
    }
}

5.執(zhí)行引擎

public class Runner {

    public static List<Result> perform(TestCase testCase, List<Parameter> testData) {
        List<Result> list = new ArrayList<>();
        System.out.println(testData.size());
        if (testData != null && testData.size() > 0) {
            for (Parameter parameter : testData) {
                // 實(shí)例化何種瀏覽器與打開什么環(huán)境由配置決定,在此不實(shí)現(xiàn)
                System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + "http://chromedriver.exe");
                WebDriver driver = new ChromeDriver();
                driver.get("http://*********保密********");
                list.add(testCase.perform(driver, parameter));
            }
        } else {
            System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + "http://chromedriver.exe");
            WebDriver driver = new ChromeDriver();
            driver.get("http://*********保密********");
            list.add(testCase.perform(driver, null));
        }
        return list;
    }
}

代碼僅作為可行性分析使用,并非最終版本。

測試代碼

public class Test {
    private static List<Parameter> parameters;

    static {
        Parameter parameter = new Parameter();
        parameter.add("userName", "userName_01");
        parameter.add("password", "password_01");
        parameter.add("captcha", "captcha_01");

        Parameter paramete1r = new Parameter();
        paramete1r.add("userName", "userName_02");
        paramete1r.add("password", "password_02");
        paramete1r.add("captcha", "captcha_02");
        parameters = new ArrayList<>();
        parameters.add(parameter);
        parameters.add(paramete1r);

    }
    //通過用戶自定義保存方法運(yùn)行
    @org.testng.annotations.Test
    public void test1() {
        TestCase tc = new TestCase();
        tc.addStep(new Step(null, "input", "id.Account", "${userName}"));
        tc.addStep(new Step(null, "input", "id.Password", "${password}"));
        tc.addStep(new Step(null, "input", "id.Captcha", "${captcha}"));
        tc.addStep(new Step(null, "click", "xpath.//input[@type='submit']"));
        Runner.perform(tc, parameters);
    }
    //通過自定義類方法運(yùn)行
    @org.testng.annotations.Test
    public void test2() {
        TestCase tc = new TestCase();
        tc.addStep(new Step(LoginPage.class, "login", "${userName}", "${password}", "${captcha}"));
        Runner.perform(tc, parameters);
    }
}

代碼執(zhí)行效果

再通過一個配置文件或者數(shù)據(jù)庫存儲PageObject類的路徑,即可通過純數(shù)據(jù)進(jìn)行驅(qū)動測試運(yùn)行,后續(xù)再持續(xù)完善用戶,任務(wù),結(jié)果等相關(guān)模塊即可打造較為完善的自動化測試平臺,如此一來,測試人員僅需在平臺中編輯測試用例與測試數(shù)據(jù)并新建相關(guān)測試任務(wù)即可。測試用例以及測試數(shù)據(jù)的格式為:

Page Method value
后臺登錄頁 輸入用戶名 ${userName}
后臺登錄頁 輸入密碼 ${password}
后臺登錄頁 輸入驗(yàn)證碼 ${captcha}
后臺登錄頁 點(diǎn)擊登陸 -
userName password captcha
userName1 password1 captcha1
userName2 password2 captcha2
userName3 password3 captcha3
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容