2

好的,将自己作为一个单独的 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));
    }
4

2 回答 2

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 文件并向其中添加<ExecutionThread apartmentState="MTA" />元素”

<?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>
于 2013-01-24T10:20:19.937 回答
1

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

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

你在那里有几件事错了..

  • 你不应该强制垃圾收集/等待终结器
  • 您不应该“盲目地”处置托管资源

并且由于您将 MailService 类设为单例,因此您的生命周期管理存在问题,因为您是如何实现 Dispose() 的。

您应该阅读有关在 .NET和MSDN 杂志上正确实现 IDisposable 接口的信息。还要考虑当您的 MailClass 对象超出范围时会发生什么。以及如何在单元测试的上下文中进行管理。

于 2013-01-23T17:03:12.403 回答