How to do TDD and unit testing in powershell?
Asked Answered
S

6

71

With MS ramming powershell into all new server products, I'm starting to (reluctantly) think I need to take it seriously. Part of "taking it seriously" is TDD. Have you found good methods to unit test power shell scripts?

I've found samples of mocking from Mr Geek Noise - but I'd really like something like RhinoMocks. Brian Hartsock has a sample of running tests on powershell strings from MS Test. A little hacky, but it seems to work.

What I want is a Powershell TDD experience that is as clean as it is in "real" languages.


Update to clarify:

The first two answers attempt to steer me away from testing Powershell. The opinions are interesting. I don't want to know if it's a good idea to test in powershell. That's a subjective question that should be asked in a different forum. I want a solution to unit testing powershell. If you think it's a bad idea (it might be), treat it as a fun academic question.

  • Yes, scripting languages glue together disparate systems. However, as already pointed out, it's also easy to mock and break seams in a dynamic language.
  • I'm not asking about "debugging". Debugging is an extremely useful topic. I'll let someone else ask it.
  • Maybe PS scripts should be simple. The language supports modularity and it is inevitable that complex processes will be implemented in PS (even if a bad idea).
  • The answer to this question is not "You can't". I can see (from linked blogs - which are a little old) that some people have made headway on the problem.

To re-state: How do you implement an automated testing of Powershell logic in the style of xUnit? Integration tests are interesting, unit tests that break dependencies most interesting.

Shiksa answered 2/6, 2009 at 16:28 Comment(2)
look at #1004924 there is a similar question with some links (PSUnit and Lee Holmes post)Vino
Never take Powershell lightly. It is incredibly powerful with minimal code.Rivy
T
47

Scott Muc has started a project for a lightweight BDD framework for PowerShell called Pester:

https://github.com/pester/Pester

Theurgy answered 4/1, 2011 at 21:31 Comment(3)
Much nicer design than PsUnit. It requires no mucking with profiles or installers. I've gitted it and will start using it this week.Shiksa
Here is a blog article by Scott about pester scottmuc.com/blog/development/…Bricky
I wrote a 3-part series on TDD for PowerShell using Pester as well -- see Practical PowerShell Unit-TestingKick
S
11

PsUnit is now updated with a framework. I had the same problem as you a few months ago and I felt PsUnit was to big and complex for the number of scripts I had to write so I wrote my own unit test framework for PS. PS have the same kind of charectaristics as other script languages likepython for example, i.e. you can override functions anywhere at any time even with scope in the test methods which is great for faking (a.k.a. mocking). That is, if you have a function or object you want to test that depends on other functions you can declare them in your test method to create a local fake implementation.

So regardles of which test framework you choose to use I'd say PS is very easy to TDD. That was my experience at least.

Spireme answered 21/8, 2009 at 5:21 Comment(1)
PsUnit is pretty sweet and lightweight.Zacharie
E
3

I think you're asking about "testing strategies" instead of TDD specifically, so I'll answer both questions.

The bulk of your work in PowerShell will be integrating a bunch of disparate systems via cmdlets and object pipes. If you want to be confident your PowerShell scripts work, put as much effort as possible into building a perfect staging environment, so as to test all these systems as accurately as possible.

Running your scripts in a perfect staging environment will be infinitely more valuable than "fleshing out your design" via TDD or "testing your code's intent" with after-the-fact unit tests.

Small notes that may help:

  • The -whatif switch exists on built-in cmdlets. Also I just found out you can do this as well: -whatif:$someBool - you'll know when you need it.
  • The ISE coming in V2 has a debugger. Sweet.
  • You can always code up a custom cmdlet in C# and do whatever you want there.
Erst answered 2/6, 2009 at 20:54 Comment(3)
Hmm ... you also doubt its possible. Note that the Geek Noise blog demonstrates a solution to mocking (the disparate systems).Shiksa
It's possible I assume, but who cares? What value is it to know that you typed "\\server\fileshare" in both your test and your script? You'll either overspecify interactions with external cmdlets, or you'll only test interactions within your own system (which will end up being a VERY small portion of your script.) I suppose that has value, but again, you'll reap a far greater benefit by doing real testing in a staging environment (and in prod itself if possible.)Erst
Neither system nor unit testing gives "far greater benefit" - both needed. If I'm testing "interactions with external cmdlets" it is not a unit test. Here's a trivial example of common logic that benefits from unit testing / mocking: We have a post-deployment script that identifies interesting errors in a windows event log - excluding spam. Posh excels here - no need for cmdlet. The filter criteria is complex and delicate. Extract the where-object criteria to function and test various inputs. Easy to come up with other examples.Shiksa
S
1

I am writing some basic PowerShell scripts with TDD like the following model:

First, the spec in SUT_spec.ps1:

Import-Module -Name .\my_SUT.ps1

$case1_input=@{}
$case1_output=@{}
f1 $case1_input $case1_output

$case1_result = $case1_output["Output"] -eq "expected"
"f1 case1: $case1_result"

# repeat for all test cases

Remove-Module -Name my_SUT

Second, my unit (SUT) as a function in my_SUT.ps1 file:

function f1($the_input, $the_output)
{
    #take input from $the_input hashtable, process it and put output into $the_output hashtable.

    $the_output["Output"]="results"
}

Third, the releasable main entry point as a separated file like SUT_spec.ps1 but with inputs from actual external sources.

Shafting answered 25/9, 2019 at 10:57 Comment(0)
C
0

Dead discussion but the concerns are very much alive.

The one thing I see missing from the discussion of the usefulness of unit testing PS given its intended use involves modules in an enterprise system. Imagine an enterprise setting with a central repository for common network-/file-level tasks implemented in PS. In this setting, you have a small number of developers and network specialists all of which have slightly overlapping duties. A developer creates a module encapsulating business logic and its usefulness is immediately acknowledged such that in no time, others jump in and incorporate the module in their own efforts. The module is included in anything from one-off interactive scripts to medium-sized client applications; While some might not agree on the use cases for a shell-scripting language, evolution is a constant in this field.

In this scenario, I believe there's value in defining a set of "contracts" for these common modules to follow. If knowledge-sharing is integral to the organization then it's possible more than one person would be modifying these modules. Having unit tests validate the integrity of the modules would go a long way towards maintaining order and minimizing chaos thus sustaining (perhaps increasing) the value of the modules themselves.

As to a preferred approach, I've yet to adopt one. PS brings to mind a fluid/dynamic/agile substance. Containing it within a rigid structure such as what I've seen with TDD feels unnatural. However, given the scenario above, this goal can't be ignored. Nevermind, I'm torn, sorry to waste your time. Thank you for reading.

Crampon answered 25/5, 2012 at 14:2 Comment(1)
This sounds somewhat similar to what I blogged about a couple of years ago under "PowerShell & .Net - Building Systems as Toolkits" - chrisoldwood.blogspot.co.uk/2011/11/…. I've written a lot of glue in PS and would feel more comfortable if I could unit test it - especially the error handling as that is often hard to simulate in a test environment.Predicament
P
-3

From your question I think you are headed for disappointment. Powershell is just a little command line language. Sure, it can do anything that C# can do, and even more, but then so can assembly language. Of course it's also OO and hooked in to the .NET libraries, but so is C#, which is a much much cleaner language.

If a solution is longer than a one liner, or you think you need to TDD it, then you don't want to be using Powershell. It's a cryptic language that is full of surprises, to be avoided for anything complicated.

If you want to do some ad hoc search and replace or formatting of text, or look around in your file system, then Powershell is your friend. What you really want to do is to use it a little every day, and repeat yourself often, in order to stay familiar with the syntax. For this reason, also avoid open source Powershell libraries, and forget about writing your own CmdLets, unless you have a very specialized case for ad hoc command line usage. The pipe binding rules are arcane and ugly.

This is all just my opinion of course, but I am a long time Powershell user and am much happier with it now that I look at it like this.

Pommel answered 2/6, 2009 at 18:32 Comment(6)
I assume that PowerShell scripts will be written because MS is pushing it hard. It will quickly become useful. Because PS scripts will be written and they will be programs (however humble), I want them to be robust. So, I want to test them. You might disagree but then, let's call this an academic exercise: how would you unit test a powershell script? The practical conclusion may be that it is too hard ( I think not impossible ) and I should use IronPython for scripting instead if I insist on quality. :)Shiksa
No one doubts that TDD in Powershell is possible. It is definitely possible, after all, Powershell can do everything C# can do, and then some. The functional nature of Powershell in theory can make it an even better testing language than C#. The problem is just that the syntax and general design of Powershell is...well, ugly, and suprising. Let's talk again after you've had a year of experience with it...Pommel
I've been using PS for at least 3 years for day to day work (mostly for robust file capabilities) - we can talk now :) I agree it's ugly. However, it hooks into a LOT of functionality. The surprises are WHY I want to test it.Shiksa
BTW, whenever I ask a Powershell question, I also tend to get answers telling me to not use Powershell, and rarely get an actual answer, so I realize that it is annoying. So sorry about that! And there are cases where Powershell is your only option, like perhaps at customer sites.Pommel
I love PowerShell, and the more I use it, and learn about it, the more I like it! I think that there is a good bunch of people like me. And don't forget that PowerShell is a now big part of Visual Studio in the form of the NuGet Package Manager Console.Vocative
Years later and I still feel the same. I am here simply because I noticed that I regularly lose points from this answer. So be it. :) That said, I am still a Powershell user, sometimes it comes in handy, it is just that every time I return to it I have to relearn it. It just won't stick. BTW sometimes a better option is JavaScript.Pommel

© 2022 - 2024 — McMap. All rights reserved.