Модульное тестирование надстройки .NET для Microsoft Office

Есть ли у кого-нибудь предложения по модульному тестированию надстройки управляемого приложения для Office? Я использую NUnit, но у меня были те же проблемы с MSTest.

Проблема в том, что внутри приложения Office (в моем случае Word) загружена сборка .NET, и мне нужна ссылка на этот экземпляр сборки .NET. Я не могу просто создать экземпляр объекта, потому что тогда у него не будет экземпляра Word, с которым можно что-то делать.

Теперь я могу использовать интерфейс Application.COMAddIns("Name of addin").Object для получения ссылки, но это дает мне COM-объект, который возвращается через RequestComAddInAutomationService. Мое решение до сих пор заключается в том, чтобы у этого объекта были прокси-методы для каждого метода в реальном объекте .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 (String memberName, BindingFlags flags, Object target, Int32 [] aWrapperTypes, MessageData и msgData)

Хотя у меня есть обходной путь, он беспорядочный и помещает много тестового кода в реальный проект, а не в тестовый проект, что на самом деле не так, как должен работать NUnit.


person Richard Gadsden    schedule 24.09.2008    source источник


Ответы (2)


Вот как я это решил.

  1. Почти все в моей надстройке запускается из метода Click кнопки в пользовательском интерфейсе. Я изменил все эти методы Click, чтобы они состояли только из простого вызова без параметров.

  2. Затем я создал новый файл (Partial Class) с именем EntryPoint, в котором было много очень коротких 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

в ThisAddin, а затем

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

в моем новом файле EntryPoints.

  1. Я добавляю новый файл AddInUtilities, который

    Публичный интерфейс IAddInUtilities

#If DEBUG Then

Sub DocMemo()

#End If

End Interface


Public Class AddInUtilities
    Implements IAddInUtilities
    Private Addin as ThisAddIn

#If DEBUG Then

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
  1. Я перехожу к файлу ThisAddIn и добавляю

    Частные утилиты Как AddInUtilities

    Защищенная функция переопределения RequestComAddInAutomationService() As Object Если утилиты — это ничто, то утилиты = New AddInUtilities(Me) End If Return утилиты End Function

И теперь можно протестировать функцию DocMemo() в EntryPoints с помощью NUnit, примерно так:

<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, а не через обработчики событий.

Но это работает!

person Richard Gadsden    schedule 03.04.2009

Рассмотрим различные фреймворки для имитации NMock, RhinoMocks и т. д., чтобы имитировать поведение Office в ваших тестах.

person Lou Franco    schedule 24.09.2008
comment
@RichardGadsden Да, это правильно, и я сделал это для Excel с помощью NSubstitute, в конце концов это было не так сложно. - person Jeremy Thompson; 09.05.2013