【问题标题】:Ncrunch all test pass first run, but fails after code change and when run all button is pressedNcrunch all test pass 第一次运行,但在代码更改和运行时按下所有按钮后失败
【发布时间】:2026-02-07 15:35:02
【问题描述】:

我正在使用 nunit 和 ninject 在 VS2012 的新 MVC 4 解决方案中运行 ncrun。

当我第一次打开解决方案时,所有 50 个左右的测试运行并成功通过。

在我进行任何代码更改(即使只是添加了一个空白区域)后,ncrunch 报告我的大部分单元测试都失败了。如果我在 ncrunch 窗口中按“运行所有测试”,也会发生同样的事情。

但是,如果您点击“运行此处可见的所有测试”按钮,所有 50 次测试再次通过,并且 ncrun 报告一切都很好。

此外,当您单独运行每个测试时,它们每次都通过。

当他们确实失败时,他们似乎在我的 ninject 设置代码中失败了

错误:ControllerTestSetup 中的 TestFixtureSetUp 失败

public class ControllerTestSetup
{

    [SetUp]
    public void InitIntegrationTest()
    {
        var context = IntegrationTestContext.Instance;
        context.Init();
        context.NinjectKernel.Load<MediGapWebTestModule>();
    }

    [TearDown]
    public void DisposeIntegrationTest()
    {
        IntegrationTestContext.Instance.Dispose();
    }
}

public class IntegrationTestContext : IDisposable
{  

    private static IntegrationTestContext _instance = null;
    private static readonly object _monitor = new object();

    private IntegrationTestContext() { }

    public static IntegrationTestContext Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_monitor)
                {
                    if (_instance == null)
                    {
                        _instance = new IntegrationTestContext();
                    }
                }
            }

            return _instance;
        }
    }
}

所有测试也在 resharper 测试运行器中运行,每次都没有问题。

有人知道是什么原因造成的吗?

我猜它与 Instance 属性中的单例锁定代码有关,但我不确定。

================================================ ================================ 进展:

我能够通过将其包装在 try catch 语句中并将错误写入输出窗口来追踪到上述 ninject 设置方法中的错误。

该异常是由于尝试多次加载模块而引起的,即使我绝对没有,也没有使用任何类型的自动模块加载。

这发生在行

LocalSessionFactoryModule.SetMappingAssemblies(() => new[] { typeof(ProviderMap).Assembly });

_kernel.Load<LocalSessionFactoryModule>();
_sessionFactory = _kernel.Get<ISessionFactory>();

其中 LocalSessionFactoryModule 是为 NinjectModule 类派生的 ninject 模块类。

为什么只有 ncrun 才会出现这种情况,我可以做些什么来解决这个问题?有没有办法检查模块是否已经加载?

【问题讨论】:

  • 我想这是线程问题,因为 NCrunch 可能会在多个线程中运行您的测试。您可以尝试将线程数减少到一个吗? (在 NCrunch 配置向导中)
  • 是的,试过了,但没有成功,同样的问题仍然存在。
  • 那可能很难。我会添加一些跟踪代码,如 Trace.WriteLine("Teardown called")Trace.WriteLine("context.Init was called") 以查看 1)失败的地方 2)所有设置和初始化代码被调用了多少次
  • 目前还没有更好的诊断方法。也许NCrunch作者可以:)

标签: c# nunit ninject ncrunch


【解决方案1】:

NCrunch 永远不会在同一进程中执行并发测试,因此除非您的测试逻辑中有多线程行为,否则可以肯定地说这不是由单例上的锁定或线程引起的问题.

由于您已经尝试禁用并行执行并且这没有产生任何影响,我假设问题不会是由测试运行程序进程之外的资源(即磁盘上的文件)的并发使用引起的。

这意味着问题几乎肯定与执行测试的顺序有关。几乎所有手动测试运行程序(包括 Resharper)都会按照定义的顺序从开始到结束运行测试。这有利于一致性,但它可以掩盖测试以不一致/随机顺序运行时可能出现的问题。 NCrunch 将按优先级顺序执行测试,还可以在测试运行之间重用测试流程,如果没有考虑到这一点,这可能会使您的测试的运行时行为有所不同。

显示(并因此调试)与序列相关的问题的一种有用方法是尝试使用 NCrunch 以手动定义的顺序运行测试。如果您在 NCrunch 测试窗口中右键单击测试,在“高级”菜单下,您将找到使用现有任务运行程序进程运行测试的选项。对你的几个测试尝试这个操作,看看你是否可以重现出现问题的序列。发生这种情况时,您应该能够轻松地将调试器用于测试并找出失败的原因。

大多数与序列相关的问题都是由未清除的静态成员引起的,因此请确保在编写每个测试时都假设现有状态可能会被进程中运行的另一个测试留下。另一种选择是确保通过拆卸测试完全清除所有状态(尽管在我看来,这通常是一种不太实用的方法)。

【讨论】:

  • 我检查了所有未清除的静态成员和状态,但由于我的所有状态都在 nunit 的设置和 TearDown 中针对每个测试进行了初始化和清除,所以我找不到任何可能导致此问题的东西。跨度>
  • 我能够通过将其包装在 try catch 语句中并将错误写入输出窗口来追踪到上述 ninject 设置方法中的错误。该异常是由于尝试多次加载模块引起的,即使我绝对没有,也没有使用任何类型的自动模块加载。为什么这只发生在 ncrun 上,我能做些什么来解决这个问题?有没有办法检查模块是否已经加载?
  • 其他可能会或可能不会产生影响的事情是尝试调整“将引用的程序集复制到工作区”NCrunch 项目级配置选项。如果 Ninject 尝试从测试工作目录动态加载程序集,此配置设置将有助于使 NCrunch 更符合手动测试运行器的行为方式。