2010-08-24 4 views
1

Je vous écris d'un simple faisceau de test unitaire dans powershellLa trace de pile de Powershell est-elle cassée?

J'ai conçu le harnais de telle sorte que ses fonctions assert prend un script bloc comme paramètre pour permettre le harnais pour exécuter le code à partir de la fonction assert et traiter les exceptions sont jetés comme un échec de test.

Si les tests échouent, je veux retourner une ligne dans le test unitaire dans lequel le test échoue. Mon plan était de le faire en prenant une stacktrace (Get-PSCallStack) au début de chaque méthode assert et d'utiliser l'information pour la seconde pile-frame qui je suppose devrait correspondre à la ligne où la fonction assert a été appelée. En pratique, j'ai trouvé que l'information fournie par PowerShell semblait erronée. La seconde pile-cadre fait référence au fichier correct comme prévu mais donne toujours le numéro de ligne auquel j'ai appelé Get-PSCallStack dans la méthode assert. Parfois, ce nombre peut être encore plus élevé que le nombre de lignes dans le fichier donné (c'est-à-dire que Location est donné comme "ScriptFile.ps1 ligne 88" mais le fichier n'a que 20 lignes).

Y a-t-il un problème avec la trace de la pile dans PowerShell ou y a-t-il quelque chose que je ne comprends pas ici?

Modifier

Comme demandé je posterai un exemple qui devrait produire les mêmes résultats

Tester.ps1

#File 1 (Tester.ps1) 
#Creates the tester object 

$tester = (New-Object PSObject); 

$tester | Add-Member -MemberType ScriptMethod -Name AssertTrue -Value { 
    param($expression); 

    $stackFrame = (GEt-PSCallStack)[1]; 

    try{ 
     $result = &$expression; 
     if($result -eq $true){ 
      $this.LogPass(); 
     }else{ 
      $this.LogFailure("Evaluation Failed expected ""$true"" got ""$false""", $stackFrame); 
     } 
    }catch [Exception]{ 
     $this.LogFailure("Unexpected exception encountered", $stackFrame); 
    } 
} 

$tester | Add-Member -MemberType ScriptMethod -Name LogPass -Value { 
    #Do nothing 
}; 

$tester | Add-Member -MemberType ScriptMethod -Name LogFailure -Value { 
    param($message, $stackFrame); 
    "Failure Encounterd"; 
    "Command: $($stackFrame.Command)" 
    "Location: $($stackFrame.Location)"; 
    "Message: $message"; 
} 

return $tester; 

TestCase.ps1

#File 2 (TestCase.ps1) 
#Runs the tests using the tester object 

$tester = &(Resolve-Path "Tester.ps1"); 

function TestFailure($tester){ 
    $expression = {$false}; 
    $tester.AssertTrue($expression); 
} 

TestFailure($tester); 

assert est appelé sur la ligne 7 de TestCas e.ps1 et la pile d'appel est capturé sur la ligne 9 de Tester.ps1

Imprime

Failure Encounterd 
Command: TestFailure 
Location: Tester.ps1: Line 9 
Message: Evaluation Failed expected "True" got "False" 

La commande est correcte, mais à la fois le fichier et la ligne sont mal

Le prochain cadre de la trace de la pile décrit correctement où TestFailure() est appelée avec son emplacement comme « TestCase.ps1: ligne 11 »

+0

Ne sachant pas vraiment quoi que ce soit au sujet de Powershell, mais il semble que peut-être un peu C# est généré à partir du script ps d'origine. La classe C# générée est ensuite exécutée, avec la stacktrace rapportant ainsi la ligne du code généré par C# et non votre script ... –

+0

Je suis presque sûr que c'est la ligne de la première pile-frame (où Get-PSCallStack est appelé – Willbill

+0

Je suis également assez sûr que PowerShell utiliserait .Net byte code directement plutôt que de passer par couche AC# (je pourrais me tromper là) – Willbill

Répondre

2

il n'est pas une assertion fonction que vous utilisez, il est un assert bloc de script utilisé comme "fonction membre". Mais c'est toujours un bloc de script.

Selon ce problème signalé: https://connect.microsoft.com/PowerShell/feedback/details/531086/depending-on-how-you-invoke-a-script-block-the-invocation-details-may-not-be-available-from-inside-the-script-block#

il y a quelque chose de mal à appeler Get-PSCallStack de blocs de script. Donc, la réponse à votre question est probablement: oui, c'est un problème de PowerShell.

Eh bien, je vous recommande d'utiliser des fonctions. J'ai re-factorisé vos scripts pour utiliser des fonctions (version corrompue, mauvais noms, etc.) Et ils fonctionnent comme prévu:

#File 1 (Tester.ps1) 
#Creates the tester object 

function AssertTrue { 
    param($expression); 

    $stackFrame = (Get-PSCallStack)[1] 

    try{ 
     $result = . $expression; 
     if($result -eq $true){ 
      LogPass 
     }else{ 
      LogFailure ("Evaluation Failed expected ""$true"" got ""$false""") $stackFrame 
     } 
    }catch [Exception]{ 
     LogFailure "Unexpected exception encountered" $stackFrame 
    } 
} 

function LogPass { 
    #Do nothing 
} 

function LogFailure { 
    param($message, $stackFrame); 
    "Failure Encounterd"; 
    "Command: $($stackFrame.Command)" 
    "Location: $($stackFrame.Location)"; 
    "Message: $message"; 
} 

Et

#File 2 (TestCase.ps1) 
#Runs the tests using the tester object 

. (Resolve-Path "Tester.ps1"); 

function TestFailure { 
    $expression = {$false}; 
    AssertTrue $expression 
} 

TestFailure 
+0

merci, cela m'a conduit le long du mur – Willbill

Questions connexes