【问题标题】:Jenkins failed unit CanExecute test's methods nondeterministicJenkins 失败单元 CanExecute 测试的方法不确定
【发布时间】:2019-06-04 12:31:12
【问题描述】:

我们对项目中的各种命令进行了很多 CanExecute 测试。 当我们使用 Visual Studio 测试或 AxoCover 时,所有测试都正确通过。

我们尝试在执行“CanExecute”之前添加一些先前的对象初始化,有时它会起作用(或者我们认为)。

testedViewModel.Object.InEditMode = inEditMode;

我有一个测试:

[TestCase(true, true, TestName = "Command_InEditMode_CanExecute")]
[TestCase(false, false, TestName = "Command_NotInEditMode_CannotExecute")]
public void CommandCanExecute(bool inEditMode, bool expectedResult)
{
    var testedViewModel =
        new Mock<SomeViewModel>(inEditMode)
        {
            CallBase = true
        };

    testedViewModel.Setup(x => x.InEditMode).Returns(inEditMode);

    Assert.AreEqual(expectedResult, testedViewModel.Object.Command.CanExecute(null));
}

有时(不总是)当 Jenkins 进行构建和运行单元测试时,一些可以执行的测试失败并显示消息:

MESSAGE:
  Expected: True
  But was:  False

+++++++++++++++++++  
STACK TRACE:
   at Project.CommandCanExecute(Boolean inEditMode, Boolean expectedResult)

问题是这种情况只发生在 Jenkins 上,而且非常不确定。

编辑:

好的,还有一件事要考虑。属性 InEditMode 放置在 SomeModelView 的基父类中。

我在示例中为您合并了代码。

public BaseViewModel 
{
    public virtual bool InEditMode {get; set;}
}

public SomeViewModel : BaseViewModel
{
    public SomeViewModel () : base ()
    {

    }

    public ICommand Command { get; set; }

    public virtual void RegisterCommands()
    {
        Command = new RelayCommand(/*Do something*/, () => InEditMode);
    }
}

我们认为这可能是相关的,该对象认为在基类初始化完成之前已初始化。但这很难用 Jenkins 来检查。


解决方案

我已经创建了一个属性类:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Assembly, AllowMultiple = true)]
public class GarbageCollectorDisabler : Attribute, ITestAction
{
    public void BeforeTest(ITest test)
    {
        GC.TryStartNoGCRegion(2048 * 4096);
    }

    public void AfterTest(ITest test)
    {
        GC.EndNoGCRegion();
    }

    public ActionTargets Targets => ActionTargets.Test;
}

然后我可以为每个 'CanExecute' 测试这个属性:

[GarbageCollectorDisabler]
[TestCase(TestName = "SomeTest_InEditMode_CanExecute")]
public void SomeTestCanExecute()
{}

【问题讨论】:

  • 您的代码中有竞速条件吗?有时我们也有类似的情况,因为我们的测试是在多个线程中执行的
  • 不,你在上面看到的代码在我们的项目中几乎完全一样。有时我们有非常简单的 CanExecute ,就像上面一样。据我所知,我们的 Jenkins 并没有在多个线程中执行测试。
  • 我添加了第二个测试用例。 CanExecute 方法在代码中。只是: () => InEditMode
  • @PiotrZieliński 在您的示例中InEditMode 不是virtual 时如何能够被覆盖?提供可用于重现问题的minimal reproducible example,以便更好地理解所询问的内容。
  • testedViewModel.Object 是模拟对象的一个​​实例。 Command 是类中的属性名称,其中包含具有匿名函数的 RelayCommand 对象。你是对的,InEditMode 是一个虚拟类型,忘记在上面的代码中添加这个。

标签: c# wpf jenkins moq canexecute


【解决方案1】:

对我来说,这听起来像是一个垃圾收集问题。尽管代码示例不完整(RegisterCommands 在哪里调用?),但我在您的示例中没有看到任何让我印象深刻的内容,因此可能缺少一些重要的内容。

查看RelayCommand.CanExecute() 的来源。它对您传入的操作进行弱引用,一旦收集到该操作CanExecute 将返回false。请参阅我的回答 here 以了解发生这种情况的示例。

我重申@Nkosi 的评论,创建一个最小的示例,而不是向我们展示点点滴滴。

【讨论】:

  • 是的,这是一个垃圾收集器问题!我将在我的原始帖子中添加解决方案。
  • @PiotrZieliński 不是该解决方案的忠实拥护者。您的代码有一个错误(某些对象未正确保留),并且在某些时候您会在非测试环境中遇到它。在测试期间禁用 GC 只会掩盖错误。
猜你喜欢
  • 2017-03-20
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-12
  • 2011-09-16
  • 2015-04-25
相关资源
最近更新 更多