Does anyone have an example of mocking a dot-sourced class function with Pester 5 and PowerShell 7?
Thank you.
Edit: example
Classes\MyClass.ps1:
class MyClass {
[void] Run() {
Write-Host "Class: Invoking run..."
}
}
MyModule.psm1:
# Import classes
. '.\Classes\MyClass.ps1'
# Instantiate classes
$MyClass = [MyClass]::new()
# Call class function
$MyClass.Run()
Pester only mocks commands - not classes or their methods.
The easiest way to "mock" a PowerShell class for method dispatch testing is by taking advantage of the fact that PowerShell marks all methods virtual, thereby allowing derived classes to override them:
class MockedClass : MyClass
{
Run() { Write-host "Invoking mocked Run()"}
}
The nice thing about this approach is that functions that constrain input to the MyClass type will still work with the mocked type:
function Invoke-Run
{
param([MyClass]$Instance)
$instance.Run()
}
$mocked = [MockedClass]::new()
Invoke-Run -Instance $mocked # this still works because [MockedClass] derives from [MyClass]
Does anyone have an example of mocking a dot-sourced class function
with Pester 5 and PowerShell 7?
You can look at this repo:
https://github.com/dsccommunity/SqlServerDsc/blob/8dde54df19ccbdb95629ec1c074e7a97acf229d2/tests/Unit/Classes/ResourceBase.Tests.ps1#L111-L165
Also, see my answer here which contains example code:
"Unable to find type" when mocking class in a Powershell unit test
Related
In powershell functions i can have something like
Function myFunction {
Param(
[Parameter(Mandatory=$True)][string]$foo,
[Parameter(Mandatory=$False)][string]$bar = "whatever"
)
....
}
But this seems limited to functions - is there something similar for method?
class MyClass {
...
[void]MethodA {
Param(
....
dont works for me.
The interpreter complains about the missing '(' in the class method parameter list.
Adding methods to classes works just like in most other scripting languages one might know. Instead of [void]MethodA {Param()...} you might want to add a block like described in this blog post or here:
class MyClass {
#...
[void]MethodA ($param) {
#...
}
}
As your title says optional parameters (but your question doesn't) a short word on that...
Usually you want multiple signatures for such cases. That means you create a method MethodA($arg1, $arg2) and a delegating method like MethodA($arg1) {MethodA($arg1, $null)}
EDITED to reduce confusion on the intended aim
Is it possible to create any sort of annotation which can apply a common pattern to a function?
An example may be a standard error-handling routine. Rather than having to implement the same try/catch structure with the error-handling function, it would be nice to have an attribute or annotation with which I could decorate the function, thus implementing the common pattern without using the same explicit code in each function.
Perhaps this is a case of trying to shoehorn PowerShell into doing something it isn't meant to do, but I'd like to avoid some of the repetition I find most common in my scripts.
You just need to inherit from ValidateArgumentsAttribute class and provide custom validation logic in Validate method:
C#:
Add-Type #‘
using System;
using System.Management.Automation;
public class ValidateIsEvenAttribute : ValidateArgumentsAttribute {
protected override void Validate(object arguments, EngineIntrinsics engineIntrinsics) {
if(LanguagePrimitives.ConvertTo<int>(arguments)%2==1) {
throw new Exception("Not even");
}
}
}
’#
PowerShell v5:
class ValidateIsOddAttribute : Management.Automation.ValidateArgumentsAttribute {
[void] Validate([object] $arguments, [Management.Automation.EngineIntrinsics] $engineIntrinsics) {
if($arguments%2-eq0) {
throw 'Not odd'
}
}
}
Then you can apply that attributes to function parameters:
function f { param([ValidateIsEven()]$i, [ValidateIsOdd()] $j) $i, $j }
f 2 1 #OK
f 2 2 #Error
f 1 1 #Error
I need $this to work inside static class! How to achieve that? Any workaround? I have analyzed return of Get-PSCallStack in class context and found nothing useful.
I need this for (a) logging and for (b) calling other static methods of same class without mentioning its name again and again.
Sample code (PowerShell v5):
class foo {
static [void]DoSomething() {
[foo]::DoAnything() #works
#$this.DoAnything #not working
$static_this = [foo]
$static_this::DoAnything() #works
}
static [void]DoAnything() {
echo "Done"
}
}
[foo]::DoSomething()
Static classes do not have this pointer. See MSDN
Static member functions, because they exist at the class level and not
as part of an object, do not have a this pointer. It is an error to
refer to this in a static method.
You must call method by class name.
I need to create a .NET object in PowerShell. The signature for the constructor is:
public ObjCTor(TClient param1, Func<TClient, IInterface> param2)
and the class is defined as:
public class ObjCTor<TClient> : IOtherInt1, IOtherInt2 where TClient : ConcreteBase
The first parameter is easy enough. I'm stumped on the second. How can I pass a PowerShell function as Func<T1, T2>?
UPDATED
PowerShell can convert a ScriptBlock to a delegate, so something like this might work fine:
$sb = { param($t1) $t1 }
New-Object "ObjCTor[CClient, Func[CClient,IInterface]]" -ArgumentList $param1,$sb
Note that PowerShell cannot deduce generic type arguments from a ScriptBlock. In your case, ObjCTor looks like a generic class so type deduction isn't a factor, but if you were calling a generic method, things could get messy.
The syntax supplied by Jason wasn't quiet correct. This works:
$= New-Object "ObjCTor[TClient]" -ArgumentList $param1,$functionToCall
I was also missing the $args[0] as a parameter in my scriptblock/delegate. This is what I should've had:
$functionToCall = { Get-Blah $args[0] }
Code:
add-type #"
public interface IFoo
{
void Foo();
}
public class Bar : IFoo
{
void IFoo.Foo()
{
}
}
"# -Language Csharp
$bar = New-Object Bar
($bar -as [IFoo]).Foo() # ERROR.
Error:
Method invocation failed because [Bar]
doesn't contain a method named 'Foo'.
You can do something like
$bar = New-Object Bar
[IFoo].GetMethod("Foo").Invoke($bar, #())
You get (the reflection representaion of) the member of IFoo from the Type object and call an Invoke overload. Too bad one has to do it that way, though.
Similar approach for explicitly implemented properties etc.
If the method takes arguments, they go in the array #() after the comma in the code above, of course.
I wrote something for PowerShell v2.0 that makes it easy to call explicit interfaces in a natural fashion:
PS> $foo = get-interface $bar ([ifoo])
PS> $foo.Foo()
See:
http://www.nivot.org/2009/03/28/PowerShell20CTP3ModulesInPracticeClosures.aspx (archived here).
It does this by generating a dynamic module that thunks calls to the interface. The solution is in pure powershell script (no nasty add-type tricks).
-Oisin
Bad news: It's a bug.
https://connect.microsoft.com/feedback/ViewFeedback.aspx?FeedbackID=249840&SiteID=99