Модульное тестирование надстройки .NET для Microsoft Office
Вопрос
У кого-нибудь есть какие-либо предложения по модульному тестированию надстройки управляемого приложения для Office?Я использую NUnit, но у меня были те же проблемы с MSTest.
Проблема в том, что внутри приложения Office загружена сборка .NET (в моем случае Word), и мне нужна ссылка на этот экземпляр сборки .NET.Я не могу просто создать экземпляр объекта, потому что тогда у него не было бы экземпляра Word, с которым можно было бы что-то делать.
Теперь я могу использовать приложение.COMAddIns ("Имя надстройки").Объектный интерфейс для получения ссылки, но это возвращает мне COM-объект, который возвращается через RequestComAddInAutomationService.Мое решение на данный момент заключается в том, чтобы у этого объекта были прокси-методы для каждого метода в реальном.ЧИСТЫЙ объект, который я хочу протестировать (все задано при условной компиляции, чтобы они исчезли в выпущенной версии).
COM-объект (a VB.NET class) на самом деле имеет ссылку на экземпляр реальной надстройки, но я попытался просто вернуть это в NUnit и получил приятную ошибку p / Invoke:
Система.Среда выполнения.Удаленное взаимодействие.Исключение RemotingException :Этот удаленный прокси-сервер не имеет приемника каналов, что означает, что либо на сервере нет зарегистрированных серверных каналов, которые прослушивают, либо у этого приложения нет подходящего клиентского канала для связи с сервером.в System.Runtime.Удаленный доступ.Прокси.RemotingProxy.InternalInvoke(IMethodCallMessage reqMcmMsg, логическое значение useDispatchMessage, тип вызова Int32) в System.Runtime.Удаленное взаимодействие.Прокси.RemotingProxy.Вызвать (запрос iMessage) в System.Runtime.Удаленный доступ.Прокси.RealProxy.PrivateInvoke(MessageData& msgData, тип Int32)
Я попытался сделать основную надстройку COM видимой, и ошибка изменилась:
Система.Исключение InvalidOperationException :Операция недопустима из-за текущего состояния объекта.в System.RuntimeType.ForwardCallToInvokeMember(Строковое имя члена, флаги BindingFlags, целевой объект, Int32[] aWrapperTypes, MessageDataи msgData)
Хотя у меня есть обходной путь, он грязный и помещает много тестового кода в реальный проект вместо тестового проекта - что на самом деле не так, как должен работать NUnit.
Решение
Вот как я решил эту проблему.
Практически все в моей надстройке запускается методом нажатия кнопки в пользовательском интерфейсе.Я изменил все эти методы Click, чтобы они состояли только из простого вызова без параметров.
Затем я создал новый файл (частичный класс) с именем EntryPoint, в котором было множество очень коротких вспомогательных файлов Friend, каждый из которых обычно представлял собой один или два вызова параметризованных рабочих функций, так что все методы 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.
Я добавляю новый файл 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
Я перехожу к файлу ThisAddIn и добавляю
Частные утилиты Как дополнительные возможности
Защищенный Переопределяет функцию RequestComAddInAutomationService() Как объект Если утилиты Ничего не значат, то утилиты = Новые дополнительные возможности (Me) Завершить, если Вернуть утилиты Завершить функцию
И теперь можно протестировать функцию DocMemo() в точках входа, используя 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, потому что вы вызываете точки входа другим способом, т. Е. через интерфейс RequestComAddInAutomationService, а не через обработчики событий.
Но это работает!