是否可以将Outlook包装为单例并使用MS UnitTesting进行测试?

时间:2013-01-23 16:59:34

标签: c# unit-testing outlook mstest

好吧,让自己成为一个单独的MailService类来使用Outlook类(它本身就是一个单独的afaik)似乎是一个好主意。

一开始它运行得很好,但是一旦我尝试从我的appservice层为这个类设置单元测试(MS单元测试),所有地狱都崩溃了,我得到Runtime Callable Wrapper错误..

我错误地将MailService类设置为单例还是将Outlook作为单例类包装出错?

这是我的Mailservice类,其中包含以下方法之一:

public class MailService : IDisposable
{

    private static MailService _instance;
    private Outlook.ApplicationClass _app;
    private Outlook.NameSpace _olNS;

    private MailService()
    {
        _app = new Outlook.ApplicationClass();
        _olNS = _app.GetNamespace("MAPI");
    }

    public static MailService Instance
    {
        get
        {
            if (_instance == null)
                _instance = new MailService();
            return _instance;
        }
    }

    public void Dispose()
    {
        _app.Quit();
        Marshal.ReleaseComObject(_app);
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

    public Outlook.Folder getFolderByPath(string sFolderPath)
    {
        Outlook.Folder olFolder = null;
        if (sFolderPath.StartsWith(@"\\"))
        {
            sFolderPath = sFolderPath.Remove(0, 2);
        }
        string[] sFolders = sFolderPath.Split('\\');
        try
        {
            olFolder = _app.Session.Folders[sFolders[0]] as Outlook.Folder;
            if (olFolder != null)
            {
                for (int i = 1; i <= sFolders.GetUpperBound(0); i++)
                {
                    Outlook.Folders subFolders = olFolder.Folders;
                    olFolder = subFolders[sFolders[i]] as Outlook.Folder;
                    if (olFolder == null)
                    {
                        return null;
                    }
                }
            }
            return olFolder;
        }
        catch (Exception e)
        {
            LogHelper.MyLogger.Error("Error retrieving " + sFolderPath, e);
            return null;
        }
    }
}

我的MS单元测试 单独工作,但在测试列表 中全部运行时则不行。在后一种情况下,只有第一次测试通过......

    [TestMethod]
    public void TestMonitorForCleanUpDone()
    {
        Assert.IsNotNull(MailService.Instance.getFolderByPath(olFolderDone));
    }

    [TestMethod]
    public void TestMonitorForCleanUpIn()
    {
        Assert.IsNotNull(MailService.Instance.getFolderByPath(olFolderIn));
    }

2 个答案:

答案 0 :(得分:1)

对于初学者来说,你对IDisposable的实现并不好。

 public void Dispose()
 {
    _app.Quit();
    Marshal.ReleaseComObject(_app);
    GC.Collect();
    GC.WaitForPendingFinalizers();
 }

你有几件事情错了..

  • 你不应该强迫垃圾收集/等待终结者
  • 你不应该“盲目地”处理托管资源。

由于您实施Dispose(),因此您正在使MailService类成为单例,因此您的生命周期管理存在问题。

您应该阅读properly implementing the IDisposable interface in .NETon MSDN Magazine here。还要考虑当MailClass对象超出范围时会发生什么。以及如何在单元测试的环境中管理它。

答案 1 :(得分:1)

像往常一样,事实证明其他人之前遇到过这个问题,并写了一篇关于它的博客文章: http://blogs.msdn.com/b/martijnh/archive/2009/12/31/unit-testing-com-object-that-has-been-separated-from-its-underlying-rcw-cannot-be-used.aspx

为了防止博客文章消失,解决方案就是在MTA模式下运行单元测试。

“解决此问题的方法是使用XML编辑器打开testrunco​​nfig文件并添加 &lt; ExecutionThread apartmentState =”MTA“/&gt; 元素对它“

<?xml version="1.0" encoding="utf-8"?>
<TestRunConfiguration name="Local Test Run" id="f3322344-5454-4ac5-82b7-fa5ba9c1d8f2"     xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
  <ExecutionThread apartmentState="MTA" />
  <Description>This is a default test run configuration for a local test run.</Description>
  <TestTypeSpecific />
</TestRunConfiguration>