Pester unit testing function with Mandatory=True - unit-testing

I'm learning slowly using the wonderful Pester unit testing for Powershell for a while now. I'm kind of stuck around the usage of checking if my function can run "if not supplied any mandatory input into a function." which is giving me a red light here and wanted to achieve a green test result and move on coding.
So I have a function as follows.
function Code()
{
param(
[parameter(Mandatory=$true)]
[string]$SourceLocation)
return "Hello from $SourceLocation"
}
my test script is executed with the following checks
...
$moduleName = 'Code';
Describe $moduleName {
Context "$Function - Returns a result " {
It "does something useful with just $Function function name" {
$true | Should Be $true
}
}
Context "$Function - Returns with no input " {
It "with no input returns Mandatory value expected" {
Code | Should Throw
}
}
Context "$Function - Returns some output" {
It "with a name returns the standard phrase with that name" {
Code "Venus" | Should Be "Hello from Venus"
}
It "with a name returns something that ends with name" {
Code "Mars" | Should Match ".*Mars"
}
}
} #End Describe
my output from AppVeyor shows this outcome which the [+] are green colours and [-] is a red colour which is what I'm avoiding the best I can.
Describing Code
Context Code - Returns a result
[+] does something useful with just Code function name 16ms
Context Code - Returns with no input
[-] with no input returns Mandatory value expected 49ms
Cannot process command because of one or more missing mandatory parameters: SourceLocation.
at <ScriptBlock>, C:\projects\code\Code.Tests.ps1: line 117
117: Code | Should Throw
Context Code - Returns some output
[+] with a name returns the standard phrase with that name 23ms
[+] with a name returns something that ends with name 11ms
Any help is appreciated as I would like a green condition there as I'm not sure how to overcome certain types of message responses from Powershell and translate this into unit tests...

Per the comment from TessellatingHeckler, your code isn't working because in order to test for Throw you need to pipe the Should cmdlet a scriptblock { }:
{Code} | Should Throw
It's worth noting however that (when testing for a mandatory parameter) this works OK in AppVeyor because PowerShell is running in a non-interactive console (PowerShell.exe -noninteractive). If you try to run your Pester tests locally, your tests will seemingly be interrupted as you get prompted for input.
There's a couple of ways around this, one is to just run your tests locally using PowerShell in noninteractive mode:
PowerShell.exe -noninteractive {Invoke-Pester}
Another is to pass the parameter an explicit $null or empty value (with the caveat that you can actually have a mandatory string parameter that accepts $null and this solution won't work necessarily with all other parameter types):
It "with no input returns Mandatory value expected" {
{Code $null} | Should Throw
}
However it is worth noting that these two solutions throw different exception messages, and you should further test for an explicit message for the Throw so that your test doesn't pass if the code is failing for some other reason. E.g:
Running with -noninteractive
It "with no input returns Mandatory value expected" {
{Code} | Should Throw 'Cannot process command because of one or more missing mandatory parameters: SourceLocation.'
}
Passing it $null
It "with no input returns Mandatory value expected" {
{Code $null} | Should Throw "Cannot bind argument to parameter 'SourceLocation' because it is an empty string."
}
In summary this is only a complex issue for this specific scenario because your parameter is mandatory and you're testing for its absence.
Testing for exceptions is generally a simple process of:
{ some code } | should Throw 'message'
And works fine in both an interactive and non-interactive console.

Related

Raku grammar action throwing "Cannot bind attributes in a Nil type object. Did you forget a '.new'?" error when using "make"

I have this method in a class that's throwing a Cannot bind attributes in a Nil type object. Did you forget a '.new'?
method parse() {
grammar FindHeaders {
token TOP { [<not-header> | <header>]+ $ }
token not-header { ^^ <![#]> \N* \n }
token header { ^^ '#'{ 1 .. 6 } <content> \n }
token content { \N+ }
}
class HeaderActions {
method content($match) {
return if $match ~~ m/^^\#\s+<[A..Z]>+e*s/ || $match !~~ m/<[a..z]>/;
return if $match ~~ m/\|/ && ( $match ~~ m:i/project/ || $match ~~ m:i/\+\w/ );
my $tc = Lingua::EN::Titlecase.new($match);
my $new_title = $tc.title;
make($new_title);
}
}
my $t = $!content;
FindHeaders.parse($t, actions => HeaderActions.new);
}
As far as I can tell, this code matches what's in the official documentation. So not sure why I'm getting this error. I have no idea what attribute or Nil object the compiler is referring to. If I comment out the line with the make method, everything works fine.
method content($match) {
There's a reason that action methods typically use $/ as the argument name: because the make function looks for $/ in order to associate the provided object to it. You can use $match, but then need to call the make method on that instead:
$match.make($new_title);
The mention of Nil is because the failed match earlier in the action method resulted in $/ being set to Nil.
I guess you avoided the more idiomatic $/ as the parameter of the action method because it gets in the way of doing further matching in the action method. Doing further matching in action methods means that the text is being parsed twice (once in the grammar and again the action), which is not so efficient, and usually best avoided (by moving the parsing work into the grammar).
As a final style point, declaring grammars and action classes in a method is neat encapsulation if they are only used there, but it would be wise to my scope them (my grammar FindHeaders { ... }), otherwise they shall end up installed in the nearest enclosing package anyway.
Err - bit of a guess here but looks like this error is generated during creation of a new object. That points to the line my $tc = Lingua::EN::Titlecase.new($match). I wonder if you want to pass a Str into this function call e.g. with "$match" or ~$match...

Cannot get Maven Archetype requiredProperty validationRegex to work

I have an archetype and I am trying to add a new requiredProperty which should only allow one of two possible values: "hibernate" and "hibernate-reactive". In the archetype-metadata.xml, I have defined the property as shown below:
<requiredProperty key="quarkus_orm_selection">
<validationRegex><![CDATA[^(hibernate|hibernate-reactive)$]]></validationRegex>
</requiredProperty>
In jshell and in other Java programs, I have verified that the regular expression works properly, but in the archetype when I test using a value like hibernate-ree the archetype proceeds without an error!
I proved out the regex as follows in JShell:
jshell> String[] examples = {"hibernate", "hibernate-reactive", "hibernate-re", "hibernate-ree", "testing", "reactive"}
examples ==> String[6] { "hibernate", "hibernate-reactive", "h ... ", "testing", "reactive" }
jshell> Pattern regex = Pattern.compile("^(hibernate|hibernate-reactive)$")
regex ==> ^(hibernate|hibernate-reactive)$
jshell> Arrays.asList(examples).stream().filter(i -> regex.matcher(i).matches()).forEach(System.out::println)
hibernate
hibernate-reactive
Can anyone suggest what I might be doing wrong?
I am using Maven Archetype Plugin version 3.2.0
As far as I can tell maven archetypes only validates reg-ex's if you pass in the property in interactive mode.
I created a archetype-post-generate.groovy script (see below)
src/main/resources/META-INF/archetype-post-generate.groovy:
String ormSelector = request.getProperties().get("quarkus_orm_selection")
def pattern = "^(hibernate|hibernate-reactive)\$" // the \$ is important!
final match = ormSelector.matches(pattern)
if (!match) {
println "[ERROR] ormSelector: $ormSelector is not valid"
println "[ERROR] please provide an ormSelector that follows this pattern: '$pattern'"
throw new RuntimeException("OrmSelector: $ormSelector is not valid")
}

Pester and testing for enum

How do I test for enum with the Powershell unit test framework Pester?
What I get back from the testee seems to be a string and not my proper enum.
Testresult
The test results in an error. What I got back was Apple and not my enum [FruitType]::Apple.
...
Expected {[FruitEnum]::Apple}, but got {Apple}.
6: $res.TheFruit | Should -Be [FruitEnum]::Apple
...
Fruit.psm1
The Powershell module here makes the enum "public" and exports a method that returns an object with my Fruit enum.
enum FruitEnum{
Apple
}
function Get-Fruit{
return #{
TheFruit = [FruitEnum]::Apple
}
}
Export-ModuleMember -Function Get-Fruit
Fruit.Tests.ps1
The Pester test calls using to get hold of the enum, calls the testee and checks the result.
using module .\Fruit.psm1
Import-Module .\Fruit.psm1 -Force
Describe "Get-Fruit" {
It "returns an enum" {
$res = Get-Fruit
$res.TheFruit | Should -Be [FruitEnum]::Apple
}
}
I have occasionally seen odd things with Pester, and used a trick such as the following to fix them:
($res.TheFruit -eq [FruitEnum]::Apple) | Should Be True
That is, perform the comparison and then check that the result is True, rather than trust that Should will be able to assert that something coming down the pipeline is the Type that you expect it to be.
Another check you could do is to verify the Type of the object:
$res.TheFruit.GetType().Fullname | Should Be "FruitEnum"

jenkins workflow regex

I'm making my first steps in the Jenkins workflow (Jenkins ver 1.609.1)
I need to read a file, line by line, and then run regex on each line.
I'm interested in the regex "grouping" type, however "project" and "status" variables (the code below) get null value in Jenkins . Any suggestions what is wrong and how to fix it ?
def line = readFile (file)
def resultList = line.tokenize()
for(item in resultList ){
(item =~ /(\w+)=(\w+)$/).each { whole, project, status ->
println (whole)
println (project)
println (status)
}
}
each with a closure will not work: JENKINS-26481
If something using advanced language features works in standalone Groovy but not in Workflow, try just encapsulating it in a method marked #NonCPS. This will effectively run it as a “native” method. Only do this for code you are sure will run quickly and not block on I/O, since it will not be able to survive a Jenkins restart.
Well,
After checking out some other regex options I came around with the following solution that seems working :
def matcher = item =~ /(?<proj>\w+)=(?<status>\w+)/
if( matcher.matches() ) { etc...}

Specs2 spec fails to compile after upgrade to latest version

I have just upgraded Specs2 on my project and now some specs won't compile and it isn't clear why they're not, here's the spec:
"fail validation if a connection is disconnected" in {
val connection = factory.create
awaitFuture(connection.disconnect)
factory.validate(connection) match {
case Failure(e) => ok("Connection successfully rejected")
case Success(c) => failure("should not have come here")
}
}
(The whole file can be seen here)
And the compiler says:
could not find implicit value for evidence parameter of type
org.specs2.execute.AsResult[Product with Serializable]
"fail validation if a connection is disconnected" in {
^
And while I understand what it is saying, it doesn't make any sense given I am returning ok or failure and I'm covering all cases on my match.
Any idea what could be wrong here?
The compiler is trying to find the common type of the 2 match branches. The first line is using ok which is a MatchResult and the second line is using failure which is returning a Result. Their only common type is Product with Serializable.
The fix is simply to use the opposite value of ok which is ko:
factory.validate(connection) match {
case Failure(e) => ok("Connection successfully rejected")
case Success(c) => ko("should not have come here")
}
You could also write
import org.specs2.execute._
...
factory.validate(connection) match {
case Failure(e) => Success("Connection successfully rejected")
case Success(c) => failure("should not have come here")
}
There is however no success(message: String) method available to match the corresponding failure. I will add it to the next specs2 version for better symmetry.