本文档由Felipe Knorr Kuhn撰写,并根据其博客上发布的一系列文章进行改编。
建模您的测试用例
在编写测试用例之前,您需要知道如何验证以及将要验证的内容。让我们使用WordPress “创建新帖子”测试用例。
- 请访问http://demo.opensourcecms.com/wordpress/wp-login.php
- 在“用户名”字段中输入“admin”
- 在“密码”字段中输入“demo123”
- 单击“登录”按钮
- 验证文本“Howdy,admin”是否存在
- 单击“帖子”链接
- 单击“添加新”按钮
- 在标题字段中输入“Selenium Demo Post”
- 单击“发布”按钮
- 验证是否存在“发布后”文本
考虑到这种情况,首先想到的是创建一个遍历所有步骤的长测试用例。如果您正在编写手动测试用例,这可能是一个很好的方法。但是,由于我们正在编写自动化测试,因此我们希望尽可能将脚本编写为模块化,以便在将来的场景中重用其中的部分内容。
这就是我打破测试的方式:
- 启动WordPress网站
- 打开“管理员登录”页面
- 输入有效的登录数据
- 导航到“写信息”页面
- 写这篇文章
- 发布帖子
- 确认它实际上是发布的
请记住,这只是一个例子。只要具有业务价值并验证业务逻辑,您就可以以任何您想要的方式为测试建模。
让我们看看如何使用实际的Java代码:
@Test (description= "Launches the WordPress site" ) |
public void launchSite(){ |
selenium.waitForPageToLoad( "30000" ); |
assertEquals(selenium.getTitle(), "Demo | Just another WordPress site" ); |
@Test (description= "Navigates to the admin page" ) |
public void openAdminPage() { |
selenium.open( "wp-admin" ); |
selenium.waitForPageToLoad( "30000" ); |
assertEquals(selenium.getTitle(), "Demo 鈥� Log In" ); |
@Test (description= "Enters valid login data" ) |
public void loginAsAdmin() { |
selenium.type( "user_login" , "admin" ); |
selenium.type( "user_pass" , "demo123" ); |
selenium.click( "wp-submit" ); |
selenium.waitForPageToLoad( "30000" ); |
assertTrue(selenium.isTextPresent( "Howdy, admin" )); |
@Test (description= "Navigates to the New Post screen" ) |
public void navigateNewPost() { |
selenium.click( "//a[contains(text(),'Posts')]/following::a[contains(text(),'Add New')][1]" ); |
selenium.waitForPageToLoad( "30000" ); |
assertTrue(selenium.isTextPresent( "Add New Post" )); |
@Test (description= "Writes the new post" ) |
public void writeBlogPost() { |
selenium.type( "title" , "New Blog Post" ); |
selenium.click( "edButtonHTML" ); |
selenium.type( "content" , "This is a new post" ); |
@Test (description= "Publishes the post" ) |
public void publishBlogPost() { |
selenium.click( "submitdiv" ); |
selenium.click( "publish" ); |
selenium.waitForPageToLoad( "30000" ); |
assertTrue(selenium.isTextPresent( "Post published." )); |
@Test (description= "Verifies the post" ) |
public void verifyBlogPost() { |
selenium.click( "//a[contains(text(),'Posts') and contains(@class,'wp-first-item')]" ); |
selenium.waitForPageToLoad( "30000" ); |
assertTrue(selenium.isElementPresent( "//a[text()='New Blog Post']" )); |
@Test (description= "Logs out" ) |
selenium.click( "//a[text()='Log Out']" ); |
这些是我们将要使用的测试方法(或步骤)。
配置方法
如果您熟悉单元测试框架,则可能了解设置和拆卸方法。TestNG超越了这个想法,允许您定义将在测试套件,测试组或测试方法之后或之前运行的方法。这对我们的Selenium测试非常有用,因为您可以在开始运行测试套件之前创建Selenium服务器和浏览器实例。)
为此,我们将使用两个TestNG 注释:@BeforeSuite和@AfterSuite:
@BeforeSuite (alwaysRun = true ) |
public void setupBeforeSuite(ITestContext context) { |
String seleniumHost = context.getCurrentXmlTest().getParameter( "selenium.host" ); |
String seleniumPort = context.getCurrentXmlTest().getParameter( "selenium.port" ); |
String seleniumBrowser = context.getCurrentXmlTest().getParameter( "selenium.browser" ); |
String seleniumUrl = context.getCurrentXmlTest().getParameter( "selenium.url" ); |
RemoteControlConfiguration rcc = new RemoteControlConfiguration(); |
rcc.setSingleWindow( true ); |
rcc.setPort(Integer.parseInt(seleniumPort)); |
server = new SeleniumServer( false , rcc); |
throw new IllegalStateException( "Can't start selenium server" , e); |
proc = new HttpCommandProcessor(seleniumHost, Integer.parseInt(seleniumPort), |
seleniumBrowser, seleniumUrl); |
selenium = new DefaultSelenium(proc); |
@AfterSuite (alwaysRun = true ) |
public void setupAfterSuite() { |
PS:你有没有注意到那些奇怪的参数?它们存储在XML文件中(我们将在下一节中看到)并由注入的ITestContext对象访问。
通过添加这些注释,TestNG引擎将在测试套件之前/之后自动调用配置方法(确保测试方法使用@Test注释),启动Selenium服务器并仅实例化Selenium客户端对象一次,重用相同的浏览器跨测试的会话。
创建XML文件
要定义测试的顺序,我们必须创建一个XML文件,列出我们想要运行的测试方法。确保测试方法使用@Test注释,否则TestNG引擎不会调用它们。
在TestNG 5.13.1之前,如果要按XML文件中定义的顺序运行测试,则必须使用方法拦截器。我已经在我的Github帐户上发布了我的方法拦截器的实现。从TestNG 5.13.1+开始,您只需将preserve-order参数添加到测试标记中,并包含您想要运行的方法,从而减少测试套件中不必要的代码。
这是XML文件:
< suite name = "Knorrium.info - Wordpress Demo" verbose = "10" > |
< parameter name = "selenium.host" value = "localhost" /> |
< parameter name = "selenium.port" value = "3737" /> |
< parameter name = "selenium.browser" value = "*firefox" /> |
< test name = "Write new post" preserve-order = "true" > |
< class name = "test.Wordpress" > |
< include name = "launchSite" /> |
< include name = "openAdminPage" /> |
< include name = "loginAsAdmin" /> |
< include name = "navigateNewPost" /> |
< include name = "writeBlogPost" /> |
< include name = "publishBlogPost" /> |
< include name = "verifyBlogPost" /> |
在Eclipse中启动测试
我们完成了测试,现在我们如何运行它们?
您可以使用Eclipse插件甚至以编程方式从命令行启动TestNG。我们将使用Eclipse插件。按照此处的官方TestNG文档中描述的步骤进行操作
如果您正确安装了TestNG,当您右键单击XML文件时,您将看到此菜单:
单击“作为TestNG Suite运行”,您的测试将开始运行。然后,您将看到这个漂亮的结果树:
思考未来
如果您真的想要考虑测试套件的未来,我建议您阅读Adam Goucher 在PragPub上发表的文章。他谈到了Selenium 2和Page Objects Model(一种非常好的模型测试方法,特别是如果你使用Selenium 2)。
由于有很多人仍在使用Selenium 1,我会坚持一段时间,但Selenium 2最终会在这里介绍。
随着测试套件中测试数量的增加,您会发现将它们分组到不同的测试类中是个好主意。如果这样做,您可以利用面向对象的编程并创建一个名为BaseTest的新类(例如),并将配置逻辑留在那里。这样,每个测试类都必须扩展BaseTest类并使用静态属性。
public class WordPressAdmin extends BaseTest { |
这比将配置方法保留在测试类中要好。