C# 是否可以将Outlook包装为singleton并使用MS UnitTesting进行测试?

C# 是否可以将Outlook包装为singleton并使用MS UnitTesting进行测试?,c#,unit-testing,outlook,mstest,C#,Unit Testing,Outlook,Mstest,好的,让我自己成为一个单独的邮件服务类来处理Outlook类(它本身就是一个单独的afaik)似乎是个好主意 起初它工作得很好,但当我尝试从appservice层为这个类设置单元测试(MS单元测试)时,所有的麻烦都爆发了,我得到了运行时可调用的包装错误 将邮件服务类设置为singleton类是错误的,还是将Outlook包装为singleton类是错误的 这是我的Mailservice类,其中一个方法如下所示: public class MailService : IDisposable {

好的,让我自己成为一个单独的邮件服务类来处理Outlook类(它本身就是一个单独的afaik)似乎是个好主意

起初它工作得很好,但当我尝试从appservice层为这个类设置单元测试(MS单元测试)时,所有的麻烦都爆发了,我得到了运行时可调用的包装错误

将邮件服务类设置为singleton类是错误的,还是将Outlook包装为singleton类是错误的

这是我的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;
        }
    }
}

首先,IDisposable的实现并不好

 public void Dispose()
 {
    _app.Quit();
    Marshal.ReleaseComObject(_app);
    GC.Collect();
    GC.WaitForPendingFinalizers();
 }
你在那里会发现一些错误

  • 您不应该强制垃圾收集/等待终结器
  • 您不应“盲目”处置托管资源
而且,由于您将MailService类设置为单例,因此您的生命周期管理是有问题的,因为您是如何实现Dispose()的


你也应该读一下。还要考虑当MailClass对象超出范围时会发生什么。以及如何在单元测试的上下文中进行管理。

与往常一样,事实证明以前有人遇到过这个问题,并为此写了一篇博文:

以防blogpost消失,简而言之,解决方案是在MTA模式下运行单元测试

“解决此问题的方法是使用XML编辑器打开testrunconfig文件,并向其中添加元素”


这是本地测试运行的默认测试运行配置。

感谢您的快速反馈。它似乎与IDisposable实现没有直接关系,因为当我删除它时,第二个单元测试仍然失败。我还使用此垃圾收集来清理excel互操作对象。。(虽然不是在Dispose函数中,而是在finally块中)感谢您为我指出Dispose方法的方向和单元测试的testcontext!这是VisualStudioUnitTesting框架的一个问题,可以通过在TestRunConfiguration上设置apartmentState=“MTA”来解决。很好的发现!但请记住我指出的关于IDisposable实现的内容。@MikyDinescu将这样做。我正在阅读博客帖子“Marshal.ReleaseComObject被认为是危险的”、“使用GC.Collect()有什么不对?”等等,并为仍然重要的部分实现了建议的Dispose模式(_app.Quit()…)
 public void Dispose()
 {
    _app.Quit();
    Marshal.ReleaseComObject(_app);
    GC.Collect();
    GC.WaitForPendingFinalizers();
 }
<?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>