Test unitaire du complément .NET pour Microsoft Office
Question
Quelqu'un a-t-il des suggestions pour le test unitaire d'un complément d'application gérée pour Office? J'utilise NUnit, mais j'ai eu les mêmes problèmes avec MSTest.
Le problème est qu’un assemblage .NET est chargé dans l’application Office (dans mon cas, Word) et j’ai besoin d’une référence à cette instance de l’assembly .NET. Je ne peux pas simplement instancier l’objet car il n’aurait alors pas d’instance de Word pour faire des choses.
Maintenant, je peux utiliser Application.COMAddIns ("Nom du complément"). Interface d'objet pour obtenir une référence, mais cela me procure un objet COM qui est renvoyé via RequestComAddInAutomationService. Ma solution jusqu’à présent est que cet objet ait des méthodes proxy pour chaque méthode de l’objet .NET réel que je souhaite tester (toutes définies dans la compilation conditionnelle afin qu’elles disparaissent dans la version publiée).
L'objet COM (une classe VB.NET) a en fait une référence à l'instance du vrai complément, mais j'ai essayé de la renvoyer à NUnit et j'ai obtenu une belle erreur p / Invoke:
System.Runtime.Remoting.RemotingException: ce proxy distant n'a pas de récepteur de canal, ce qui signifie que le serveur n'a aucun canal de serveur enregistré en cours d'écoute ou que cette application n'a pas de canal client approprié pour communiquer avec le serveur. sur System.Runtime.Remoting.Proxies.RemotingProxy.InternalInvoke (IMethodCallMessage reqMcmMsg, Utilisation booléenne, EnvoiDispatchMessage, Int32 callType) à System.Runtime.Remoting.Proxies.RemotingProxy.Invoke (IMessage reqMsg) sur System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke (MessageData & amp; msgData, type Int32)
J'ai essayé de rendre visible le complément principal COM et le changement d'erreur:
System.InvalidOperationException: l'opération n'est pas valide en raison de l'état actuel de l'objet. à System.RuntimeType.ForwardCallToInvokeMember (String memberName, indicateurs BindingFlags, Object target, Int32 [] aWrapperTypes, MessageData & msgData)
Pendant que j'ai une solution de travail, c'est désordonné et met beaucoup de code de test dans le projet réel au lieu du projet de test - ce qui n'est pas vraiment la façon dont NUnit est censé fonctionner.
La solution
Voici comment je l'ai résolu.
-
À peu près tout dans mon complément provient de la méthode Click d'un bouton de l'interface utilisateur. J'ai changé toutes ces méthodes Click pour ne consister qu'en un simple appel sans paramètre.
-
J'ai ensuite créé un nouveau fichier (Classe partielle) appelé EntryPoint, qui contenait beaucoup de très courts Subs Subs, chacun consistant généralement en un ou deux appels à des fonctions de travail paramétrées, de sorte que toutes les méthodes Click qui venaient d'être appelées ce fichier. Ainsi, par exemple, une fonction ouvre un document standard et appelle un "enregistrer sous". dans notre DMS. La fonction prend un paramètre du document à ouvrir et nous utilisons une douzaine de documents standard.
Donc j'ai
Private Sub btnMemo_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, ByRef CancelDefault As Boolean) Handles btnMemo.Click
DocMemo()
End Sub
dans le ThisAddin puis
Friend Sub DocMemo()
OpenDocByNumber("Prec", 8862, 1)
End Sub
dans mon nouveau fichier EntryPoints.
-
J'ajoute un nouveau fichier AddInUtilities contenant
Interface publique IAddInUtilities
#Si DEBUG alors
Sub DocMemo()
#Fin si
End Interface
Public Class AddInUtilities
Implements IAddInUtilities
Private Addin as ThisAddIn
#Si DEBUG alors
Public Sub DocMemo() Implements IAddInUtilities.DocMemo
Addin.DocMemo()
End Sub
#Fin si
Friend Sub New(ByRef theAddin as ThisAddIn)
Addin=theAddin
End Sub
End Class
-
Je vais dans le fichier ThisAddIn et ajoute dans
Utilitaires privés en tant qu'AddInUtilities
Fonctions de substitution protégées RequestComAddInAutomationService () As Object Si les utilitaires ne sont rien alors utilities = New AddInUtilities (Me) Fin si Utilitaires de retour Fonction de fin
Et maintenant, il est possible de tester la fonction DocMemo () dans EntryPoints en utilisant NUnit, à peu près comme ceci:
<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
La seule chose que vous ne pouvez pas ensuite tester à l'unité est les événements Click réels, car vous appelez dans EntryPoints d'une manière différente, c'est-à-dire via l'interface RequestComAddInAutomationService plutôt que via les gestionnaires d'événements.
Mais ça marche!
Autres conseils
Examinez les divers cadres moqueurs NMock , RhinoMocks , etc. pour simuler le comportement d'Office dans vos tests.