James's profileJames McCaffreyBlogLists Tools Help

Blog


    October 26

    Using .NET Framework Code from PowerShell

    One of the coolest things about Windows PowerShell (Microsoft's new command shell and scripting language) is that PowerShell code can call .NET code. You can think of the .NET Framework as a huge library of pre-written code. This allows you to easily perform tasks that aren't possible with the old cmd.exe shell and .BAT files. Here's an example PowerShell script that sends an HTTP request for a Web page, retrieves the response as HTML, and displays the result.
     
    # file: gethtml.ps1
     
    [System.Console]::WriteLine("Begin .NET demo`n")
    $uri = "
    http://localhost/hello.html"
    $wc = new-object System.Net.WebClient
    $b = $wc.DownloadData($uri)
    $e = [System.Text.Encoding]::ASCII
    $s = $e.GetString($b)
    write-output $s
     
    # end script
     
    These commands could also be issued interactively in a PowerShell shell environment. The first statement calls the static WriteLine() method to print a message. Of course I don't need .NET for this but it demonstrates how to call a static method. You can think of a static method as "good-to-go", meaning you simply call the method (using the correct syntax of course). Notice I use the PowerShell escape character (`) instead of the .NET escape character (\) to cause a newline after the start-up message. The next statement sets a string to my HTML target file. The third line of my script creates a new WebClient object, preparing to call an instance method. Most .NET methods are instance methods and you can think of them as methods which need to have a master object created before you can use these methods. On the fouth line I call the DownloadData() instance method. Notice it is attached to my $wc object, and that it returns an array of bytes which I store into a $b variable. Next I create an Encoding object using the static mechanism (this is a bit unusual because ::ASCII is actually a Property rather than a method). On the sixth line I use the GetString() instance method (attached to my Encoding object) to convert my result, which is currently in bytes, into a string. I finish by displaying my result string which yields:
     
    Begin .NET demo
     
    <html>
    <body>
    <p>Hello to you PowerShell</p>
    </body>
    </html>
     
    So, the moral is that you can in fact call .NET code from PowerShell scripts. It's too early to tell exactly how useful this ability is but I can see all kinds of possibilities for developers, testers, managers, and IT engineers.
    October 20

    Searching through Files with PowerShell

    Windows PowerShell is the new command line shell and language that will be released soon. I've been poking around with PowerShell and the more I see of it the better I like it. I rarely use the old cmd.exe shell for test automation tasks because it just doesn't have the horsepower to do much. A good example is searching through the file system for a text string. Here's a tiny PowerShell script that searches the current directory and all sub-directories for .txt files which contain the string "orange":
     
    # findtext.ps1
     
    $target = "orange"
    $files = get-childitem -recurse -include *.txt
    $matches = $files | select-string $target
    $results = $matches | group -property filename
    write-output $results
     
    # end script
     
    The '#' symbol is a comment line. Variables, such as $target, are preceded with a '$' character. The "get-childitem" is a cmdlet which fetches an object -- this is a key concept to PowerShell and the source of much of its power. The statement retrieves a set of all .txt files from the current directory and all sub-directories, and stores that set into $files. Next I use the select-string cmdlet to grab information about the set of all files which contain the target ("orange"). Then I group that information by filename into object $results. Finally I use the write-output cmdlet to display the results, which might look like:
     
    Count Name                      Group
    ----- ----                      -----
        2 Colors.txt                {Colors.txt, Colors.txt}
        1 Fruits.txt                {Fruits.txt}
     
    This shows the script found a total of three occurrences of "orange". The target was found in two different but identically named Colors.txt files, and also in a "Fruits.txt" file. Pretty cool. I can easily parameterize my script by replacing the first statement with:

    $target = $args[0]
     
    Then I can run my script like:
     
    PS C:\Data\Alpha> C:\Data\Alpha\findtext.ps1 orange
     
    This will run my findtext.ps1 script, and search for "orange" in all .txt files in directory Alpha and all of Alpha's sub-directories.
    October 14

    Model-Based Testing

    Model-Based Testing (MBT) is a term to describe a software testing methodology. The basic idea of MBT is that you create a model of the system under test (SUT), and then MBT tools can automatically generate and execute test cases. If you are not a software engineer, you can think of a model as similar to a blueprint for a building, or to a schematic diagram for an electrical circuit. While model-based testing sounds great in principle, MBT is rarely successful in practice. The problem is not MBT as such; rather, the problem is with factors associated with the construction and maintenance of the model of the system under test. Broadly speaking, there are three ways to generate the model of a software system. The first approach to model-creation is to write code, and then manually create the model that corresponds to the code. This approach generally fails because the code and the model get out of synchronization, because in most scenarios the code base of the SUT changes too quickly, and the effort required is very big. The second approach to model-creation is to write code, and then use a tool to automatically generate the corresponding model. This approach fails because no tool can generate state transition information (e.g., if the user clicks button A and dropdown B currently has "foo" then textbox C should display "bar"), unless the SUT code explicitly contains such state transition information -- and this requires huge effort. The third approach to model-creation is to create the model first (including state transition information), and then use a tool which will automatically generate source code from the model. This approach is sometimes called model-based architecture (MBA). The MBA approach can in fact work, but is enormously expensive, and so is limited to gigantic software systems. In such a situation -- a huge software system under development with vast resources being developed using model-based architecture -- model-based testing can be feasible as one component of a testing effort. That said, there are precious few actual examples of successful model-based testing.
    October 06

    Scripting Languages vs. Non-Scripting Languages in Test Automation

    I've used both scripting languages (Perl, Python, JavaScript, VBScript) and non-scripting languages (C, C++, C#, VB.NET, Java) to write test automation. Lately I've been writing the majority of my application code with C# and I've been using C# for my test automation too. When writing test automation, the two standard arguments for using the same, non-scripting language as used to create your application to test your system are that 1.) Non-scripting languages and development environments are more powerful, and 2.) That using the same language reduces test automation logic errors such as those generated by differences in data types. So, if those arguments are true then testing a C# application using test automation written in C# makes good sense. The single standard argument for using a scripting language for test automation is that scripting languages are very lightweight and have low overhead -- just launch notepad, type, and run, as opposed to the pain of using a heavyweight tool such as Visual Studio. So, if that argument is true then testing a C# application using Python makes sense too. However, I've been experimenting with Microsoft's new IronPython (essentially a "Python.NET") and noticed a couple of things about these standard arguments. First, there is really very little advantage nowadays to the lightweight aspect of scripting languages. Firing up and using Visual Studio requires virtually no more effort than using notepad these days, as opposed to the old days of separate compilers, editors, linkers, and help files running on machines with limited resources. So, at first thought, if the single advantage of using scripting languages for test automation is gone, then I should argue to always use the non-scripting C# (or similar) language for test automation. However, I noticed that when using the IronPython scripting language, I was forced out of my mental comfort zone and really thought about my test automation. I believe this is the true advantage of using a scripting language for test automation instead of using the same, non-scripting language you use to create your application -- you become more creative. The bottom line is that if you write test automation, I think you need both scripting language skills and non-scripting language skills in order to maximize your testing productivity and value to your company or team.

    Rank Order Centroids in Testing, Part II

    In an earlier post, I described rank order centroids, and their relationship to software testing. The basic problem, for which rank order centroids provide one solution, is to transform ranks (such as 1st, 2nd, 3rd, and so forth) into a set of rating metrics which sum to 1.0. For example, in my post on rank order centroids, if there were five items ranked 1st through 5th, then the corresponding ratings for the four items are 0.5208, 0.2708, 0.1458, and 0.0625. Let me describe a less sophisticated, but valid, alternate technique to convert ranks to ratings normalized on a [0.0 to 1.0] scale. This other technique is called rank sum weights (RSW), or equi-interval weights (EIW). It is easily explained by example. Suppose we have five items, A, B, C, D, E ranked 1st, 2nd, 3rd, 4th, 5th respectively. To compute rank sum weights, you sum the ranks (1 + 2 + 3 + 4 + 5 = 15), then divide each rank complement by the sum. So, A: 5 / 15 = 0.3333 and B: 4 / 15 = 0.2667 and C: 3 / 15 = 0.2000 and D: 2 / 15 = 0.1333 and E: 1 / 15 = 0.0667. Easy!  Notice that the interval between each rating is the same (0.0667) which is why the technique can be called an equi-interval weight. To summarize:

    Item  Rank   ROC     RSW
    ============================
    A     1st    0.4567  0.3333
    B     2nd    0.2567  0.2667
    C     3rd    0.1567  0.2000
    D     4th    0.0900  0.1333
    E     5th    0.0400  0.0667
                ----------------
    Sum          1.0000  1.0000