【问题标题】:Why do my tests fail when run together, but pass individually?为什么我的测试一起运行时失败,但单独通过?
【发布时间】:2012-02-17 17:21:26
【问题描述】:

当我在 Visual Studio 中编写测试时,我会通过保存、构建然后在 Nunit 中运行测试来检查它是否有效(右键单击测试然后运行)。

测试成功了... 所以我继续...

现在我已经编写了另一个测试,它可以像上面一样保存和测试它。但是,它们一起运行时不起作用。

这是我的两个测试,单独运行时有效,但一起运行时失败:

using System;
using NUnit.Framework;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium;

namespace Fixtures.Users.Page1
{
    [TestFixture]
    public class AdminNavigateToPage1 : SeleniumTestBase
    {
        [Test]
        public void AdminNavigateToPage1()
        {
            NavigateTo<LogonPage>().LogonAsCustomerAdministrator();
            NavigateTo<Page1>();
            var headerelement = Driver.FindElement(By.ClassName("header"));

            Assert.That(headerelement.Text, Is.EqualTo("Page Title"));
            Assert.That(Driver.Url, Is.EqualTo("http://localhost/Page Title"));
        }

        [Test]
        public void AdminNavigateToPage1ViaMenu()
        {
            NavigateTo<LogonPage>().LogonAsCustomerAdministrator();
            Driver.FindElement(By.Id("menuitem1")).Click();
            Driver.FindElement(By.Id("submenuitem4")).Click();
            var headerelement = Driver.FindElement(By.ClassName("header"));

            Assert.That(headerelement.Text, Is.EqualTo("Page Title"));
            Assert.That(Driver.Url, Is.EqualTo("http://localhost/Page Title"));
        }
    }
}

当第二个测试因为它们一起运行而失败时

Nunit 展示了这个:

Sse.Bec.Web.Tests.Fixtures.ManageSitesAndUsers.ChangeOfPremises.AdminNavigateToChangeOfPremises.AdminNavigateToPageChangeOfPremisesViaMenu: OpenQA.Selenium.NoSuchElementException : 找不到元素

这一行被突出显示:

var headerelement = Driver.FindElement(By.ClassName("header"));

有谁知道为什么我的代码一起运行时失败,但单独运行时通过?

任何答案将不胜感激!

【问题讨论】:

  • 你确定测试不是共享状态吗?浏览器是否在测试之间关闭并重新打开?当它们一起运行时,哪个测试失败了?两个都失败了,还是一个通过,一个失败?
  • 浏览器关闭,命令窗口也关闭。它们再次重新打开以处理以下测试......它是第一个通过的测试,然后所有后续测试通常都会失败,并且它们总是同样失败原因张贴在上面。
  • 对您的具体问题没有帮助,但请查看ncrunch.net,它会在后台运行您的测试。摆脱整个“保存、构建然后运行测试”的麻烦。
  • 这一直发生在我身上(尽管有不同的错误),尽管我正在访问数据库并在事务中运行每个测试。我得到非线程安全异常,所以当通过 Visual 运行时Studio下一个测试必须在上一个测试完成之前开始(运行命令行似乎没有同样的问题)

标签: c# visual-studio-2010 selenium-ide nunit-2.5


【解决方案1】:

查看TestFixtureSetupSetupTestFixtureTearDownTearDown
这些属性允许您设置一次测试环境,而不是每次测试一次。

【讨论】:

  • 你有什么建议我可以在 TestFixtureTearDown 中清理?
  • @GraemeSecondwave 不幸的是我不知道 Selenium。但是,我确实知道,当我一起运行测试时,它们会失败,而当我将常用指令添加到设置中时,它会起作用。例如,如果将 NavigateTo&lt;LogonPage&gt;().LogonAsCustomerAdministrator(); 添加到 TestFixtureSetup 会发生什么?
  • 如果var headerelement... 行被突出显示,则可能是它之前的行引发了异常。确保 submenuitem4 存在。你试过调试它吗? (右键单击您的测试,选择 Test With -> Debugger)
【解决方案2】:

您确定在运行其中一项测试后该方法

NavigateTo<LogonPage>().LogonAsCustomerAdministrator();

要带你回到你应该去的地方吗?失败似乎是由于导航处理程序不当造成的(假设在两个测试中都存在并找到了 header 元素)。

【讨论】:

  • 很好地观察驱动程序在我的测试中导航,它会加载所有页面并按预期导航到页面。和我正在寻找的页面标题显示。它不喜欢“标题元素”作为测试,因为它自己运行时通过了?
【解决方案3】:

你可以尝试两件事

  1. 在以下两行之间放置断点。并在点击第二行时查看您在哪个页面

  2. 通过 Thread.Sleep 在这两行之间引入一点延迟

    Driver.FindElement(By.Id("submenuitem4")).Click();
    var headerelement = Driver.FindElement(By.ClassName("header"));
    

【讨论】:

  • 尝试了您建议的 thread.sleep 功能。在我添加它之前,当我运行测试时,它总是第二个测试失败,但是使用命令 sleep 它总是第二个测试过去,第一个测试失败?奇怪!
  • 所以这可能意味着您需要在“header”元素查找器上方的thread.sleep,以便在您的驱动器查找该元素之前为浏览器提供足够的时间来加载页面。在第一次测试中也尝试相同的方法。
  • 好的,我在两个测试中都添加了睡眠功能,它们已经通过了!奇怪的是我以前试过但从来没有把它们加到两者上。不知道为什么它们现在通过了,但我越发不高兴了!感谢您的帮助。
  • thread.sleep 可能不是“为什么会这样”问题的答案。我使用 selenium 驱动程序单击基于 css 的菜单的经验并不那么可预测。 Thread.Sleep 似乎是我能够可靠地处理这些点击的唯一方法
【解决方案4】:

在不知道 Selenium 的工作原理的情况下,我押注Driver,这似乎是一个静态类,因此 2 个测试共享状态。共享状态的一个示例是Driver.Url。因为测试是并行运行的,所以有一个竞争条件来设置这个对象的状态。

也就是说,我没有适合你的解决方案:)

【讨论】:

    【解决方案5】:

    如果以上答案都不适合您,我通过在失败测试中的断言之前添加Thread.Sleep(1) 解决了这个问题...

    看起来测试同步在某处丢失了...请注意我的测试不依赖于顺序,我没有任何静态成员或外部依赖。

    【讨论】:

    • +1 因为你让我意识到我的静态对象是我的错误的问题和原因。谢谢!
    【解决方案6】:

    我认为您需要确保您可以登录进行第二次测试,这可能会失败,因为您已经登录了?

    -> 将登录置于 设置方法 或(因为您似乎在两个测试中使用相同的用户)甚至直到 fixture 设置 -> 注销(如果需要)可能会放在拆卸方法中

         [SetUp]
         public void LaunchTest()
         {
            NavigateTo<LogonPage>().LogonAsCustomerAdministrator();
         }
    
         [TearDown]
         public void StopTest()
         {
            // logoff
         }
         [Test]
         public void Test1()
         {...}
         [Test]
         public void Test2()
         {...}
    

    如果 DOM 有延迟而不是 thread.sleep,我建议结合条件使用 webdriver.wait。睡眠可能在 80% 中起作用,而在其他情况下则不起作用。等待轮询直到达到更可靠且可读的超时。这是我通常如何处理的示例:

        var webDriverWait = new WebDriverWait(webDriver, ..);
        webDriverWait.Until(d => d.FindElement(By.CssSelector(".."))
            .Displayed))
    

    【讨论】:

      【解决方案7】:

      这种情况通常发生在单元测试以某种方式使用共享资源/数据时。

      1. 如果您的被测系统具有静态字段/属性,这些字段/属性被用来计算您断言的输出,也会发生这种情况。
      2. 如果被测系统正在共享(静态)依赖项,则可能会发生这种情况。

      【讨论】:

      • 我在 .net 核心中使用 InMemory 数据库时遇到了这种情况——只是不知道如何解决它
      • 为了避免这个问题,并从可读性的角度确保测试是独立的,我通常不依赖单元测试之间的共享对象。我在每个单元测试中创建单独的对象。您可以使用不同的方法来创建不同的对象(以避免一次又一次地重写相同的代码)。
      • 这是给我的,我在测试类上有一个共享的公共属性,它代表一些基础数据的起点。我必须在每个测试中初始化这个对象以消除错误
      • 我在 pytest 单元测试中激活了翻译,但不知道在测试后它没有被退回。后来的测试失败了,因为它依赖于基础语言。在 Django 中,解决方案是使用with translation.override(...) 上下文管理器。
      猜你喜欢
      • 2021-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 2021-08-27
      • 1970-01-01
      • 1970-01-01
      • 2015-07-15
      相关资源
      最近更新 更多