TestNG - 工厂和数据提供者

时间:2010-06-01 18:16:33

标签: java unit-testing selenium testng webdriver

背景故事

我在一家开发测试自动化框架的软件公司工作,以取代我们旧的意大利面条纠结系统。

由于我们的系统几乎需要登录我们所做的一切,我决定最好使用@ BeforeMethod,@ DataProvider和@Factory来设置我的测试。但是,我遇到了一些问题。

样本测试用例

让我们说软件系统是棒球队的名单。我们要测试以确保用户可以按名称搜索团队成员。

(注意:我知道BeforeMethods没有以任何给定的顺序运行 - 假设现在已经处理过了。)

@BeforeMethod
public void setupSelenium() {
    // login with username & password
    // acknowledge announcements
    // navigate to search page
}

@Test(dataProvider="players")
public void testSearch(String playerName, String searchTerm) {
    // search for "searchTerm"
    // browse through results
        // pass if we find playerName
    // fail (Didn't find the player)
}

此测试用例假设如下:

  • 用户已登录(最有可能是在BeforeMethod中)
  • 用户已导航到搜索页面(简单,方法之前)
  • 测试参数与上述登录
  • 相关联

问题

因此,让我们试着弄清楚如何处理测试用例的参数。

创意#1

此方法允许我们将数据提供者与用户名相关联,并允许我们将多个用户用于任何特定的测试用例!

@Test(dataProvider="players")
public void testSearch(String user, String pass, String name, String search) {
    // login with user/pass
    // acknowledge announcements
    // navigate to search page
    // ...
}

...但是有很多重复,因为我们必须让每个函数都接受两个额外的参数。更不用说,我们还测试了确认公告功能,我们实际上并不想测试它。

创意#2

因此,让我们使用工厂正确初始化事物!

class BaseTestCase {

    public BaseTestCase(String user, String password, Object[][] data);

}

class SomeTest {

    @Factory
    public void ...

}

有了这个,我们最终必须为每个测试用例编写一个工厂......虽然,它确实让每个测试用例拥有多个用户。

结论

我的想法很新鲜。我有另一个想法,我从XML文件加载数据,然后从程序中调用方法......但它变得愚蠢。

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

首先,您似乎在尝试在每个测试用例中做太多。例如,如果您正在搜索某些内容,为什么还需要将导航作为搜索的一部分进行测试?

其次,您的要求似乎不清楚。您可以创建一个测试,在其中发送一个搜索词并获得单个结果吗?看起来这应该是你的第一次测试。

第三,为什么授权会话连接/对象不能成为测试的要求?从代码的外观来看,您似乎正在通过HTTP进行某种调用。即使你不是,看起来你必须使用某种经纪人向你的应用发送消息,因为你必须传递用户名并传递每个请求...为什么不自动化整个进入“授权经纪人”对象的东西,它为您提供了一种方式来发送您的请求沿预先授权的连接?

然后只需将授权代理传递到您的测试中即可处理您的消息传递。或者更好的是,在预测试(BeforeMethods?)函数中设置授权代理,并将其作为类成员变量提供。

答案 1 :(得分:2)

我仍然不确定我理解你的问题......

您是否对第二次尝试不满意,即每个测试用例必须编写一个@Factory?那为什么不把@Factory注释放在基类构造函数上呢?这样,你所有的子类需要做的就是调用super,你就完成了。

你想要达到什么目的?

答案 2 :(得分:1)

Cederic,

我应该从第一天起开帐户,我实际上不能再编辑我的旧帖子,或回复评论(此时)。让我试着稍微扩展一下。

这是我到目前为止所提出的一个例子。我想我回答了自己的问题......这很有效,但有点讨厌。

我现在的问题是,我在一家工厂进行了所有测试。由于几个原因,这并不好。一,我必须手工添加它们(或反射它们)。第二,我必须把所有东西都当作一个套件运行。有什么想法吗?

package example2;

import java.lang.reflect.Method;
import java.util.HashMap;
import org.testng.annotations.*;

public class WebTestBase {

  protected String host, username, password;
  protected HashMap<String, Object[][]> dataSet;

  public WebTestBase(String host, String username, String password, HashMap<String, Object[][]> dataSet) {
    this.host = host;
    this.username = username;
    this.password = password;
    this.dataSet = dataSet;
  }

  @DataProvider(name="dataSet")
  public Object[][] dataSet(Method m) {
    return dataSet.get(m.getName());
  }

  @BeforeMethod
  public void login() {
    System.out.println("Logging in to " + host + " with " + username + ":" + password);
  }

  @AfterMethod
  public void logout() {
    System.out.println("Logging out!");
  }
}

package example2;

import java.util.HashMap;

import org.testng.annotations.Factory;

public class WebTestFactory {
  @Factory
  public Object[] factory() {
    HashMap<String, Object[][]> dataSetOne = new HashMap<String, Object[][]>();
    dataSetOne.put("searchRoster", new Object[][] {
          {"mcguire", "McGuire, Mark"},
          {"ruth", "Ruth, Babe"}
        });

    HashMap<String, Object[][]> dataSetTwo = new HashMap<String, Object[][]>();
    dataSetTwo.put("addPlayer", new Object[][] {
          {"Sammy Sosa", 0.273}
        });

    Object[] tests = new Object[] { 
        new SearchTest("localhost", "user", "pass", dataSetOne),
        new AddTest("localhost", "user", "pass", dataSetTwo)
      };

    return tests;
  }
}

package example2;

import java.util.HashMap;
import org.testng.annotations.Test;

public class SearchTest extends WebTestBase {

  public SearchTest(String host, String username, String password,
      HashMap<String, Object[][]> dataSet) {
    super(host, username, password, dataSet);
  }

  @Test(dataProvider="dataSet")
  public void searchRoster(String searchTerm, String playerName) {
    System.out.println("Searching for " + searchTerm);
    System.out.println("I found " + playerName + " in the search results!");
  }

}

package example2;

import java.util.HashMap;

import org.testng.annotations.Test;

public class AddTest extends WebTestBase {

  public AddTest(String host, String username, String password,
      HashMap<String, Object[][]> dataSet) {
    super(host, username, password, dataSet);
  }

  @Test(dataProvider="dataSet")
  public void addPlayer(String playerName, double battingAvg) {
    System.out.println("Adding " + playerName + " with avg " + battingAvg);
  }
}