Pester and testing for enum - unit-testing

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"

Related

How to check the value of a local variable in puppet unit test?

I have the following (simplified) setup:
mymod/manifests/as/myressource.pp:
define mymod::as::myressource (
Integer $abc,
) {
notice('mymod::as::myressource start ...')
$maxheap3 = '3G'
notice("maxheap3 = ${maxheap3}")
}
mymod/manifests/init.pp:
class mymod(
Optional[String] $maxheap,
) {
notice("${title} wird installiert...")
mymod::as::myressource {'no.1':
abc => 35
}
mymod::as::myressource {'no.2':
abc => 70
}
}
mymod/spec/classes/sometest.rb:
describe 'mymod' do
on_supported_os.each do |os, os_facts|
context "on #{os}" do
let(:facts) { os_facts }
let(:params) { {
} }
it { is_expected.to compile }
it { is_expected.not_to contain_mymod__as__myressource('no.3') }
it { is_expected.to contain_mymod__as__myressource('no.1').with({
:abc => 35,
# :maxheap3 => '3G'
}) }
end
end
end
The test works without errors, but if I uncomment the line with maxheap3 it fails and tells me:
"expected that the catalogue would contain Mymod::As::Myressource[no.1] with maxheap3 set to "3G" but it is set to nil"
How comes it, that I can check the value of a parameter in this manner, but not a local variable? What can I do to check the value of $maxheap3 in my test?
How comes it, that I can check the value of a parameter in this manner, but not a local variable?
Unit tests with Rspec puppet test the contents of the catalog. The catalog contains class and resource parameters, but it does not contain information about local variables.
What can I do to check the value of $maxheap3 in my test?
You cannot test local variables, at least not directly, and you should not want to do. They are an implementation detail. You can, however, test their impact on classes and resources that appear in the catalog. That may take the form of how many or which resources of given types are declared, which classes are declared, what values class and resource parameters take, among others.
In your example case, the value of $maxheap3 in your mymod::as::myressource instances has no impact on the catalog at all, so you cannot test it via Rspec tests. But so what? That it has no effect on the catalog means that it does not affect how Puppet configures target nodes, so at the level of Rspec_puppet, it does not matter.

Does the Perl compiler need to be told not to optimize away function calls with ignored return values?

I am writing new Perl 5 module Class::Tiny::ConstrainedAccessor to check type constraints when you touch object attributes, either by setting or by getting a default value. I am writing the unit tests and want to run the accessors for the latter case. However, I am concerned that Perl may optimize away my accessor-function call since the return value is discarded. Will it? If so, can I tell it not to? Is the corresponding behaviour documented? If the answer is as simple as "don't worry about it," that's good enough, but a reference to the docs would be appreciated :) .
The following MCVE succeeds when I run it on my Perl 5.26.2 x64 Cygwin. However, I don't know if that is guaranteed, or if it just happens to work now and may change someday.
use 5.006; use strict; use warnings; use Test::More; use Test::Exception;
dies_ok { # One I know works
my $obj = Klass->new; # Default value of "attribute" is invalid
diag $obj->accessor; # Dies, because the default is invalid
} 'Bad default dies';
dies_ok {
my $obj = Klass->new;
$obj->accessor; # <<< THE QUESTION --- Will this always run?
} 'Dies even without diag';
done_testing();
{ package Klass;
sub new { my $class = shift; bless {#_}, $class }
sub check { shift; die 'oops' if #_ and $_[0] eq 'bad' }
sub default { 'bad' }
sub accessor {
my $self = shift;
if(#_) { $self->check($_[0]); return $self->{attribute} = $_[0] } # W
elsif(exists $self->{attribute}) { return $self->{attribute} } # R
else {
# Request to read the attribute, but no value is assigned yet.
# Use the default.
$self->check($self->default); # <<<---- What I want to exercise
return $self->{attribute} = $self->default;
}
} #accessor()
} #Klass
This question deals with variables, but not functions. perlperf says that Perl will optimize away various things, but other than ()-prototyped functions, it's not clear to me what.
In JavaScript, I would say void obj.accessor();, and then I would know for sure it would run but the result would be discarded. However, I can't use undef $obj->accessor; for a similar effect; compilation legitimately fails with Can't modify non-lvalue subroutine call of &Klass::accessor.
Perl doesn't ever optimize away sub calls, and sub calls with side effects shouldn't be optimised away in any language.
undef $obj->accessor means something similar to $obj->accessor = undef

Powershell Azure Pester Test

Below is a simple function that just creates a resource group and exports the data. I am trying to learn unit test but I cant seem to figure it out.
Is it possible to give the test mock data? and can I test if the output file would work?
function New-AzureRG{
param([string]$rgName,
[string]$location
)
$getData = New-AzureRmResourceGroup -Name $rgName -location 'WestEurope'
$getData | Export-Csv $location
}
Describe "New-AzureRG" {
Context "Function Exists" {
It "Should return a message" {
$sum = New-AzureRG -rgName testRG -location C:\tst\testsc.csv
($um).Name | Should Be "testRG"
}
}
}
Here is my terrible attempt to make a test using pester. For some reason the test is actually doing it, instead of making it as a test. Im just confused :(.
I do not think your test is actually working. For example in the test $um is not assigned... If you mock the New-AzureRG function in your current test you are testing nothing. I guess you want something like:
Make a function c
Call the function from an other function
Mock the New-AzureRG function in your test
You mock can look something like:
Mock New-AzureRG { return #{Name = "NameRG"} } -ParameterFilter { $Name -eq "NameRG" }

Pester unit testing function with Mandatory=True

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.

Mocked class not accepting instance of Carbon

I am trying to test a method with PhpUnit and Mockery. In the process of specifying a method should be called with arguments my test fails.
TEST:
$this->eventRepo = \Mockery::mock('Path\To\EventRepository');
$start = Carbon::createFromFormat('Ymd-H-i-s', '20141211-09-21-00');
$end = Carbon::createFromFormat('Ymd-H-i-s', '20141211-09-19-00');
$this->eventRepo
->shouldReceive('findEvent')
->withArgs([
$start,
$end,
'1',
'1234567891'
])
->andReturn($callEvent);
REAL CODE:
$start = Carbon::createFromFormat('Ymd-H-i-s', '20141211-09-20-00');
$end = Carbon::createFromFormat('Ymd-H-i-s', '20141211-09-20-00');
$event = $this->eventRepo->findEvent(
$start->subSeconds(60),
$end->addSeconds(60),
$id,
$number
);
ERROR FROM TEST:
Mockery\Exception\NoMatchingExpectationException: No matching handler found for EventRepo::findEvent(object(Carbon\Carbon), object(Carbon\Carbon), "1", "1234567891"). Either the method was unexpected or its arguments matched no expected argument list for this method
$this->eventRepo is a mocked in the test. The real code runs correctly. After the error displays, it, I guess var_dump()'s a instance of Carbon.
I have no idea what could be causing this. I tried googling it but not knowing what to google made that pretty worthless. Has anyone run into this before?
When using an object in with() or withArgs(), phpunit performs an === check. This means that it'll look for the exact same instance of the class, not just any instance of Carbon.
In this case, it means that findEvent() is receiving an instance of Carbon, but not the exact same instance that you have in the actual code.