41 votes

Quelle est la meilleure façon de tester une application MS Access ?

Le code, les formulaires et les données se trouvant dans la même base de données, je me demande quelles sont les meilleures pratiques pour concevoir une suite de tests pour une application Microsoft Access (disons pour Access 2007).

L'un des principaux problèmes liés au test des formulaires est que seuls quelques contrôles ont une fonction hwnd et les autres contrôles n'en obtiennent qu'un seul s'ils ont le focus, ce qui rend l'automatisation assez opaque puisqu'il n'est pas possible d'obtenir une liste de contrôles sur un formulaire pour agir dessus.

Une expérience à partager ?

17voto

Philippe Grondier Points 6697

J'ai apprécié les réponses de Knox et de David. Ma réponse se situera quelque part entre les leurs : il suffit de faire les formulaires qui n'ont pas besoin d'être débogués ¡!

Je pense que les formulaires devraient être utilisés exclusivement pour ce qu'ils sont à la base, c'est-à-dire une interface graphique seulement ce qui signifie qu'ils ne doivent pas être débogués ! Le travail de débogage se limite alors à vos modules et objets VBA, ce qui est beaucoup plus facile à gérer.

Il y a bien sûr une tendance naturelle à ajouter du code VBA aux formulaires et/ou aux contrôles, surtout quand Access vous offre ces superbes événements "after Update" et "on change", mais je vous le conseille vivement no pour placer tout code spécifique au formulaire ou au contrôle dans le module du formulaire. Cela rend la maintenance et la mise à jour très coûteuses, lorsque votre code est réparti entre les modules VBA et les modules de formulaires/contrôles.

Cela ne signifie pas que vous ne pouvez plus utiliser cette AfterUpdate événement ! Il suffit de mettre un code standard dans l'événement, comme ceci :

Private Sub myControl_AfterUpdate()  
    CTLAfterUpdate myControl
    On Error Resume Next
    Eval ("CTLAfterUpdate_MyForm()")
    On Error GoTo 0  
End sub

Où ?

  • CTLAfterUpdate est une procédure standard exécutée chaque fois qu'un contrôle est mis à jour dans un formulaire.

  • CTLAfterUpdateMyForm est une procédure spécifique exécutée à chaque fois qu'un contrôle est mis à jour sur MyForm

J'ai alors 2 modules. Le premier est

  • utilityFormEvents
    où j'aurai mon événement générique CTLAfterUpdate

Le second est

  • MyAppFormEvents
    contenant le code spécifique de toutes les formes spécifiques de l'application MyApp et incluant la procédure CTLAfterUpdateMyForm. Bien entendu, la procédure CTLAfterUpdateMyForm peut ne pas exister s'il n'y a pas de code spécifique à exécuter. C'est pourquoi nous transformons la procédure "En cas d'erreur" en "Reprendre le suivant" ...

Le choix d'une solution aussi générique est très important. Cela signifie que vous atteignez un niveau élevé de normalisation du code (ce qui signifie une maintenance sans douleur du code). Et lorsque vous dites que vous n'avez pas de code spécifique aux formulaires, cela signifie également que les modules de formulaires sont entièrement normalisés et que leur production peut se faire de la manière suivante automatisé Il suffit de préciser les événements que l'on souhaite gérer au niveau du formulaire/contrôle et de définir la terminologie des procédures génériques/spécifiques.
Écrivez votre code d'automatisation, une fois pour toutes.
Cela demande quelques jours de travail mais donne des résultats passionnants. J'utilise cette solution depuis 2 ans et c'est clairement la bonne : mes formulaires sont entièrement et automatiquement créés à partir de zéro avec un "Forms Table", lié à un "Controls Table".
Je peux alors consacrer mon temps à travailler sur les procédures spécifiques du formulaire, le cas échéant.

La normalisation du code, même avec MS Access, est un processus long. Mais le jeu en vaut la chandelle !

6voto

Ray Vega Points 30187

Un autre avantage de Access étant une application COM est que vous pouvez créer un NET pour exécuter et tester une application Access via Automation . L'avantage est que vous pouvez alors utiliser un cadre de test plus puissant tel que NUnit pour écrire des tests assert automatisés contre une application Access.

Par conséquent, si vous maîtrisez C# ou VB.NET et que vous disposez d'un outil comme NUnit, vous pouvez plus facilement créer une couverture de test plus importante pour votre application Access.

5voto

mwolfe02 Points 11452

J'ai pris une page de Doctest de Python et mis en œuvre une procédure DocTests dans Access VBA. Il ne s'agit évidemment pas d'une solution de test unitaire à part entière. Elle est encore relativement jeune, et je ne pense pas avoir résolu tous les bogues, mais je pense qu'elle est suffisamment mûre pour être diffusée dans la nature.

Il suffit de copier le code suivant dans un module de code standard et d'appuyer sur F5 à l'intérieur du module pour le voir à l'œuvre :

'>>> 1 + 1
'2
'>>> 3 - 1
'0
Sub DocTests()
Dim Comp As Object, i As Long, CM As Object
Dim Expr As String, ExpectedResult As Variant, TestsPassed As Long, TestsFailed As Long
Dim Evaluation As Variant
    For Each Comp In Application.VBE.ActiveVBProject.VBComponents
        Set CM = Comp.CodeModule
        For i = 1 To CM.CountOfLines
            If Left(Trim(CM.Lines(i, 1)), 4) = "'>>>" Then
                Expr = Trim(Mid(CM.Lines(i, 1), 5))
                On Error Resume Next
                Evaluation = Eval(Expr)
                If Err.Number = 2425 And Comp.Type <> 1 Then
                    'The expression you entered has a function name that ''  can't find.
                    'This is not surprising because we are not in a standard code module (Comp.Type <> 1).
                    'So we will just ignore it.
                    GoTo NextLine
                ElseIf Err.Number <> 0 Then
                    Debug.Print Err.Number, Err.Description, Expr
                    GoTo NextLine
                End If
                On Error GoTo 0
                ExpectedResult = Trim(Mid(CM.Lines(i + 1, 1), InStr(CM.Lines(i + 1, 1), "'") + 1))
                Select Case ExpectedResult
                Case "True": ExpectedResult = True
                Case "False": ExpectedResult = False
                Case "Null": ExpectedResult = Null
                End Select
                Select Case TypeName(Evaluation)
                Case "Long", "Integer", "Short", "Byte", "Single", "Double", "Decimal", "Currency"
                    ExpectedResult = Eval(ExpectedResult)
                Case "Date"
                    If IsDate(ExpectedResult) Then ExpectedResult = CDate(ExpectedResult)
                End Select
                If (Evaluation = ExpectedResult) Then
                    TestsPassed = TestsPassed + 1
                ElseIf (IsNull(Evaluation) And IsNull(ExpectedResult)) Then
                    TestsPassed = TestsPassed + 1
                Else
                    Debug.Print Comp.Name; ": "; Expr; " evaluates to: "; Evaluation; " Expected: "; ExpectedResult
                    TestsFailed = TestsFailed + 1
                End If
            End If
NextLine:
        Next i
    Next Comp
    Debug.Print "Tests passed: "; TestsPassed; " of "; TestsPassed + TestsFailed
End Sub

Copier, coller et exécuter le code ci-dessus à partir d'un module nommé Module1 donne :

Module: 3 - 1 evaluates to:  2  Expected:  0 
Tests passed:  1  of  2

Quelques remarques rapides :

  • Il n'a pas de dépendances (lorsqu'il est utilisé à partir d'Access).
  • Il utilise Eval qui est une fonction dans le modèle d'objet Access.Application ; cela signifie que vous pourrait l'utiliser en dehors d'Access, mais cela nécessiterait de créer un objet Access.Application et de qualifier complètement l'objet Access.Application. Eval appels
  • Il y a quelques idiosyncrasies associées aux Eval être conscient de
  • Il ne peut être utilisé que pour les fonctions qui renvoient un résultat tenant sur une seule ligne

Malgré ses limites, je pense qu'il offre un bon rapport qualité-prix.

Editer : Voici une fonction simple avec des "règles doctest" que la fonction doit satisfaire.

Public Function AddTwoValues(ByVal p1 As Variant, _
        ByVal p2 As Variant) As Variant
'>>> AddTwoValues(1,1)
'2
'>>> AddTwoValues(1,1) = 1
'False
'>>> AddTwoValues(1,Null)
'Null
'>>> IsError(AddTwoValues(1,"foo"))
'True

On Error GoTo ErrorHandler

    AddTwoValues = p1 + p2

ExitHere:
    On Error GoTo 0
    Exit Function

ErrorHandler:
    AddTwoValues = CVErr(Err.Number)
    GoTo ExitHere
End Function

5voto

paulroho Points 508

Bien qu'il s'agisse d'une réponse très ancienne :

Il y a AccUnit un cadre de test unitaire spécialisé pour Microsoft Access.

4voto

Knox Points 1543

Je concevrais l'application de manière à ce que le plus de travail possible soit effectué dans les requêtes et les sous-programmes vba, de sorte que vos tests pourraient consister à alimenter des bases de données de test, à exécuter des ensembles de requêtes de production et de vba sur ces bases de données, puis à examiner les résultats et à les comparer pour s'assurer qu'ils sont corrects. Cette approche ne permet évidemment pas de tester l'interface graphique, vous pourriez donc compléter les tests par une série de scripts de test (j'entends par là un document Word qui dit d'ouvrir le formulaire 1 et de cliquer sur le contrôle 1) qui sont exécutés manuellement.

Le niveau d'automatisation nécessaire pour les tests dépend de l'ampleur du projet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X