2

わかりました。Outlookクラス(それ自体はシングルトンafaikです)を操作するために、自分自身をシングルトンとしてMailServiceクラスにするのは良い考えのように思えました。

最初はうまく機能しましたが、appserviceレイヤーからこのクラスの単体テスト(MS単体テスト)を設定しようとすると、すべてが壊れて、RuntimeCallableWrapperエラーが発生しました。

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

手始めに、IDisposableの実装は良くありません。

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

あなたはそこでいくつかの間違いを犯しています。

  • ガベージコレクションを強制したり、ファイナライザーを待ったりしないでください
  • 管理対象リソースを「盲目的に」廃棄しないでください

また、MailServiceクラスをシングルトンにしているため、Dispose()の実装方法が原因で、ライフサイクル管理に問題があります。

.NETおよびMSDNMagazineのIDisposableインターフェイスの適切な実装についてはこちらをご覧ください。また、MailClassオブジェクトがスコープ外になったときに何が起こるかについても考えてください。そして、それが単体テストのコンテキストでどのように管理されるか。

于 2013-01-23T17:03:12.403 に答える
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 に答える