Microsoft Office .NET加载项的单元测试
有没有人对单元测试Office的托管应用程序加载项有任何建议?我正在使用NUnit,但MSTest遇到相同的问题。
问题是在Office应用程序(在我的情况下为Word)中加载了.NET程序集,我需要对该.NET程序集实例的引用。我不能只实例化该对象,因为它当时没有Word实例来执行操作。
现在,我可以使用Application.COMAddIns(" addin的名称").Object接口来获取引用,但这将获得一个通过RequestComAddInAutomationService返回的COM对象。到目前为止,我的解决方案是使该对象对我要测试的真实.NET对象中的每个方法都具有代理方法(所有方法都在条件编译下设置,因此它们在发行版中消失了)。
COM对象(一个VB.NET类)实际上具有对实际加载项实例的引用,但是我尝试将其返回给NUnit并得到一个很好的p / Invoke错误:
System.Runtime.Remoting.RemotingException:此远程代理没有通道接收器,这意味着服务器没有正在侦听的注册服务器通道,或者此应用程序没有合适的客户端通道可以与服务器通信。
在System.Runtime.Remoting.Proxies.RemotingProxy.InternalInvoke(IMethodCallMessage reqMcmMsg,布尔useDispatchMessage,Int32 callType)
在System.Runtime.Remoting.Proxies.RemotingProxy.Invoke(IMessage reqMsg)
在System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&msgData,Int32类型)
我尝试使主加载项COM可见,并且错误发生了变化:
System.InvalidOperationException:由于对象的当前状态,操作无效。
在System.RuntimeType.ForwardCallToInvokeMember处(字符串memberName,BindingFlags标志,对象目标,Int32 [] aWrapperTypes,MessageData和msgData)
虽然我有一个解决方法,但它很凌乱,并且在真实项目中放置了许多测试代码,而不是在测试项目中放置了代码,这并不是NUnit工作的真正方式。
解决方案
考虑各种模拟框架NMock,RhinoMocks等,以在测试中伪造Office的行为。
这就是我解决的方法。
- 外接程序中的几乎所有内容都从UI中的按钮的Click方法运行。我已经将所有那些Click方法更改为仅包含一个简单的无参数调用。
- 然后,我创建了一个名为EntryPoint的新文件(局部类),该文件具有许多非常短的Friend Sub,每个子通常通常是对参数化工作函数的一两个调用,以便所有Click方法都被调用到该文件中。因此,例如,有一个函数可以打开标准文档,并在我们的DMS中调用"另存为"。该函数带有要打开哪个文档的参数,并且我们使用了几十个标准文档。
所以我有
Private Sub btnMemo_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, ByRef CancelDefault As Boolean) Handles btnMemo.Click DocMemo() End Sub
在ThisAddin中,然后
Friend Sub DocMemo() OpenDocByNumber("Prec", 8862, 1) End Sub
在我的新EntryPoints文件中。
- 我添加了一个新的具有公共接口IAddInUtilities的AddInUtilities文件
#If DEBUG然后
Sub DocMemo()
`#End If``
End Interface Public Class AddInUtilities Implements IAddInUtilities Private Addin as ThisAddIn
#If DEBUG然后
Public Sub DocMemo() Implements IAddInUtilities.DocMemo Addin.DocMemo() End Sub
#End If
Friend Sub New(ByRef theAddin as ThisAddIn) Addin=theAddin End Sub End Class
- 我转到ThisAddIn文件并添加私有实用程序,作为受保护的AddInUtilities覆盖函数RequestComAddInAutomationService()作为对象如果实用程序没有内容,那么Utility = New AddInUtilities(Me)如果返回实用程序结束函数
现在可以使用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事件,因为我们以不同的方式(即通过RequestComAddInAutomationService接口而不是通过事件处理程序)调用EntryPoints。
但这有效!