Port of schuchert.wikispaces.com


PowerShell5-Tokenize_Expression-First_Failing_Test

PowerShell5-Tokenize_Expression-First_Failing_Test

Up Next–>

First Failing Test

Now it’s time to create the first test. We’ll start with a failing test, and do something simple to get it to work.

    Describe "Tokenizing an in-fix expression" {
    
      It "Should convert a single number into a single token" {
        $tokenizer = [Tokenizer]::new()
    
        $tokens = $tokenizer.interpret("42")
    
        $tokens[0] | Should be "42"
      }
    }
    PS C:\Users\Brett\shunting_yard_algorithm> Invoke-Pester
    Executing all tests in '.'
    
    Executing script C:\Users\Brett\shunting_yard_algorithm\Tokenizer.Tests.ps1
    
      Describing Tokenizing an in-fix expression
        [-] Should convert a single number into a single token 58ms
          RuntimeException: Unable to find type [Tokenizer].
          at <ScriptBlock>, C:\Users\Brett\shunting_yard_algorithm\Tokenizer.Tests.ps1: line 4
    Tests completed in 58ms
    Tests Passed: 0, Failed: 1, Skipped: 0, Pending: 0, Inconclusive: 0

This failed, and it seems it failed for a reasonable reason. It doesn’t know about the type Tokenizer. To remedy this, we’ll create a module and import it into the test.

    class Tokenizer {
    }
    using module '.\Tokenizer.psm1'
    
    Describe "Tokenizing an in-fix expression" {
    # ...
    PS C:\Users\Brett\shunting_yard_algorithm> Invoke-Pester
    Executing all tests in '.'
    
    Executing script C:\Users\Brett\shunting_yard_algorithm\Tokenizer.Tests.ps1
    
      Describing Tokenizing an in-fix expression
        [-] Should convert a single number into a single token 69ms
          RuntimeException: Method invocation failed because [Tokenizer] does not contain a method named 'interpret'.
          at <ScriptBlock>, C:\Users\Brett\shunting_yard_algorithm\Tokenizer.Tests.ps1: line 8
    Tests completed in 69ms
    Tests Passed: 0, Failed: 1, Skipped: 0, Pending: 0, Inconclusive: 0

Closer, let’s get to a passing test. Again, we’ll do just enough to get the test passing.

    using namespace System.Collections
    
    class Tokenizer {
      [ArrayList]interpret([String]$expression) {
        $result = [ArrayList]::new()
        $result.Add($expression)
        return $result
      }
    }
    PS C:\Users\Brett\shunting_yard_algorithm> Invoke-Pester
    Executing all tests in '.'
    
    Executing script C:\Users\Brett\shunting_yard_algorithm\Tokenizer.Tests.ps1
    
      Describing Tokenizing an in-fix expression
        [-] Should convert a single number into a single token 47ms
          RuntimeException: Method invocation failed because [Tokenizer] does not contain a method named 'interpret'.
          at <ScriptBlock>, C:\Users\Brett\shunting_yard_algorithm\Tokenizer.Tests.ps1: line 8
    Tests completed in 47ms
    Tests Passed: 0, Failed: 1, Skipped: 0, Pending: 0, Inconclusive: 0

This might be unexpected. If so, that’s good because when unexpected thigns happen, we’re about to learn something.

In this case, running Pester directly as we are updates the current shell. There are several solutions, but a trivial one is to run “powershell invoke-pester”:

    PS C:\Users\Brett\shunting_yard_algorithm> powershell invoke-pester
    Executing all tests in '.'
    
    Executing script C:\Users\Brett\shunting_yard_algorithm\Tokenizer.Tests.ps1
    
      Describing Tokenizing an in-fix expression
        [+] Should convert a single number into a single token 683ms
    Tests completed in 683ms
    Tests Passed: 1, Failed: 0, Skipped: 0, Pending: 0, Inconclusive: 0

Summary

There are many common complaints about TDD in such a simple start:

I’m not going to even try to convince you that this does or does not work. We’ll work through the problem taking an extremely incremental approach. We’ll build up a solid footing so we can experiment later. Even so, this trivial example has demonstrated several (possibly incorrect) decisions:

Now that we have an API, we can focus on trying to grow the algorithm to make it work with at least the examples listed above.

Initialize And Initial Push

    PS C:\Users\Brett\shunting_yard_algorithm> git init
    Initialized empty Git repository in C:/Users/Brett/shunting_yard_algorithm/.git/
    PS C:\Users\Brett\shunting_yard_algorithm> git add .\Tokenizer.*
    PS C:\Users\Brett\shunting_yard_algorithm> git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
            new file:   Tokenizer.Tests.ps1
            new file:   Tokenizer.psm1
    PS C:\Users\Brett\shunting_yard_algorithm> git commit -m "Initial commit"
    [master (root-commit) 94fee3e] Initial commit
     2 files changed, 17 insertions(+)
     create mode 100644 Tokenizer.Tests.ps1
     create mode 100644 Tokenizer.psm1
    PS C:\Users\Brett\shunting_yard_algorithm> git status
    On branch master
    nothing to commit, working tree clean

Up Next–>


Comments

" Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.