【问题标题】:Application.Current is Null for Unit Tests对于单元测试,Application.Current 为 Null
【发布时间】:2012-09-19 12:03:53
【问题描述】:

我在代码库中有一些方法依赖于 Application.Current.Dispatcher.Invoke... 以确保事情在 GUI 线程上运行。我目前正在尝试为这些方法编写单元测试,但(如预期的那样)Application.Current 为空,所以我得到了 NullReferenceException。

我尝试按照此处的建议在他们自己的 AppDomain 中运行受影响的测试:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/786d5c06-0511-41c0-a6a2-5c4e44f8ffb6/

但是当我这样做时,Application.Current 仍然为空。不应该启动 AppDomain 为我设置 Application.Current 吗?为什么还是空?

我的代码: 基类:

[TestClass()]
[Serializable]
public class UnitTest
{
    protected void ExecuteInSeparateAppDomain(string methodName)
    {
        AppDomainSetup appDomainSetup = new AppDomainSetup();
        appDomainSetup.ApplicationBase = Environment.CurrentDirectory;
        AppDomain appDomain = AppDomain.CreateDomain(methodName, null, appDomainSetup);

        try
        {
            appDomain.UnhandledException += delegate(object sender, UnhandledExceptionEventArgs e)
            {
                throw e.ExceptionObject as Exception;
            };

            UnitTest unitTest = appDomain.CreateInstanceAndUnwrap(GetType().Assembly.GetName().Name, GetType().FullName) as UnitTest;

            MethodInfo methodInfo = unitTest.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);

            if (methodInfo == null)
            {
                throw new InvalidOperationException(string.Format("Method '{0}' not found on type '{1}'.", methodName, unitTest.GetType().FullName));
            }

            try
            {
                methodInfo.Invoke(unitTest, null);
            }
            catch (System.Reflection.TargetInvocationException e)
            {
                throw e.InnerException;
            }
        }
        finally
        {
            AppDomain.Unload(appDomain);
        }
    }
}

调用单元测试(包含在继承自 UnitTest 的类中):

[TestMethod()]
public void QualifierViewModel_FlagsAndLoadDatasets()
{
    ExecuteInSeparateAppDomain("TestLoadDataSets");
}

【问题讨论】:

  • 你为什么要对 GUI 代码进行单元测试?如果它依赖于 GUI,它就不是严格的单元测试。您的代码能否考虑到它对 Application.Current 的使用?
  • 这是一个视图模型,但显然集成得太紧密了。我想这实际上更像是一个集成测试而不是一个单元测试。不,我现在不能真正考虑 Application.Current 的使用(我只是应该进行单元测试,而不是接触代码)。
  • Application.Current 对象只有在 GUI 已初始化时才会存在,例如Dispatcher.Run 已被调用。这通常不会在单元测试中完成(或推荐)...
  • 我可以通过调用 new Application() 来伪造它(请参阅下面的解决方法)。但我真的不喜欢将所有这些测试都放在一个方法中。我真正想做的是让它可用于不同方法(和线程)中的测试。

标签: c# mstest nullreferenceexception applicationdomain


【解决方案1】:

此解决方法对我有用:

[TestClass]
public class MockAppTests
{
    private static Application application = new Application() { ShutdownMode= ShutdownMode.OnExplicitShutdown };
}

[TestClass]
public class IntegrationTests : MockAppTests
{        
    [TestMethod]
    public void MyTest()
    {
        //test
    }
}

【讨论】:

    【解决方案2】:

    所以现在我有一个讨厌的解决方法。我基本上将所有使用 Application.Current 的测试方法移动到一个测试中(因此它们都将在同一个线程上)并调用 new Application()。

    讨厌的代码:

    [TestClass]
        public class IntegrationTests
        {
            private CedarFile testCedarFile;
    
            /// <summary>
            /// This test tests methods that utilize Application.Current. 
            /// They all have to be in the same test because they must run on the same thread to use the Application instance.
            /// </summary>
            [TestMethod]
            public void IntegrationTests_All()
            {
                new Application();
    
                QualifierViewModel_FlagsAndLoadDatasets();
                CurrentFilesViewModel_AddCedarFile();
                CurrentFilesViewModel_AddCedarFileReadOnly();
            }
    ... the private methods to test ...
    }
    

    【讨论】:

    • 我正在测试的对象只是访问 Application.Current.Properties 所以这对我也有用。
    • 尝试使用您的解决方案时,我收到以下错误“调用线程无法访问此对象,因为不同的线程拥有它。”
    【解决方案3】:

    尝试删除Serializable 属性,改为从MarshalByRefObject 派生UnitTest 类。

    【讨论】:

    • 不,Application.Current 仍然为空,所以我仍然得到 NullReferenceException
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-01
    • 1970-01-01
    • 2019-10-03
    • 1970-01-01
    • 2018-06-15
    相关资源
    最近更新 更多