English 中文(简体)
Microsoft Office.NET外接程序的单元测试
原标题:
  • 时间:2008-09-24 11:09:22
  •  标签:

有人对Office托管应用程序外接程序的单元测试有什么建议吗?我正在使用NUnit,但我在使用MSTest时也遇到了同样的问题。

问题是在Office应用程序(在我的例子中是Word)中加载了一个.NET程序集,我需要对该.NET程序集实例的引用。我不能只是实例化对象,因为它不会有Word的实例来做事情。

现在,我可以使用Application.COMAddIns(“插件名称”).Object接口来获取引用,但这会为我获取通过RequestComAddInAutomationService返回的COM对象。到目前为止,我的解决方案是,让该对象为我想要测试的真实.NET对象中的每个方法都有代理方法(所有这些方法都是在条件编译下设置的,这样它们就会在发布的版本中消失)。

COM对象(一个VB.NET类)实际上有一个对实际外接程序实例的引用,但我尝试将其返回到NUnit,得到了一个很好的p/Invoke错误:

System.Runtime.Remoting.RemotingException : This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server. at System.Runtime.Remoting.Proxies.RemotingProxy.InternalInvoke(IMethodCallMessage reqMcmMsg, Boolean useDispatchMessage, Int32 callType) at System.Runtime.Remoting.Proxies.RemotingProxy.Invoke(IMessage reqMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

我尝试使主加载项COM可见,但错误发生了更改:

System.InvalidOperationException : Operation is not valid due to the current state of the object. at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)

虽然我有一个变通办法,但它很混乱,并将大量测试代码放在实际项目中,而不是测试项目中——这并不是NUnit真正的工作方式。

最佳回答

我就是这样解决的。

  1. 我的加载项中的几乎所有内容都是从UI中按钮的Click方法运行的。我已经更改了所有这些Click方法,使其仅由一个简单的、无参数的调用组成。

  2. 然后,我创建了一个名为EntryPoint的新文件(Partial Class),该文件有很多非常短的Friend Subs,每个Friend Subs通常是对参数化辅助函数的一两次调用,所以所有的Click方法都被调用到这个文件中。因此,例如,有一个函数可以打开一个标准文档,并将“另存为”调用到我们的DMS中。该函数获取要打开的文档的参数,并且我们使用了几十个标准文档。

所以我有

Private Sub btnMemo_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, ByRef CancelDefault As Boolean) Handles btnMemo.Click
    DocMemo()
End Sub

然后

Friend Sub DocMemo()
    OpenDocByNumber("Prec", 8862, 1)
End Sub

在我的新EntryPoints文件中。

  1. 我添加了一个新的AddInUtilities文件,该文件具有

    公共接口IAddInUtilities

#如果调试,则

Sub DocMemo()

#End如果

End Interface


Public Class AddInUtilities
    Implements IAddInUtilities
    Private Addin as ThisAddIn

#如果调试,则

Public Sub DocMemo() Implements IAddInUtilities.DocMemo
    Addin.DocMemo()
End Sub

#End如果

 Friend Sub New(ByRef theAddin as ThisAddIn)
     Addin=theAddin
 End Sub
 End Class
  1. 我转到ThisAddIn文件并添加

    作为AddInUtilities的专用公用程序

    Protected Overrides Function RequestComAddInAutomationService() As Object If utilities Is Nothing Then utilities = New AddInUtilities(Me) End If Return utilities End Function

现在可以使用NUnit在EntryPoints中测试DocMemo()函数,如下所示:

<TestFixture()> Public Class Numbering

Private appWord As Word.Application
Private objMacros As Object

<TestFixtureSetUp()> Public Sub LaunchWord()
    appWord = New Word.Application
    appWord.Visible = True

    Dim AddIn As COMAddIn = Nothing
    Dim AddInUtilities As IAddInUtilities
    For Each tempAddin As COMAddIn In appWord.COMAddIns
        If tempAddin.Description = "CobbettsMacrosVsto" Then
            AddIn = tempAddin
        End If
    Next
    AddInUtilities = AddIn.Object
    objMacros = AddInUtilities.TestObject


End Sub

<Test()> Public Sub DocMemo()


    objMacros.DocMemo()
End Sub

<TestFixtureTearDown()> Public Sub TearDown()
    appWord.Quit(False)
End Sub

End Class

唯一不能进行单元测试的是实际的Click事件,因为您以不同的方式调用EntryPoints,即通过RequestComAddInAutomationService接口而不是通过事件处理程序。

但它有效!

问题回答

考虑各种嘲讽框架N锁定RhinoMocks等,以在测试中伪造Office的行为。





相关问题
热门标签