diff --git a/.gitignore b/.gitignore
index 0b3f986..69a4344 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,5 @@ gen/generated
 .DS_Store
 Output/
 .dotnet/
+coverage.xml
+testResults.xml
\ No newline at end of file
diff --git a/src/Tests/Public/Add-CCMGroup.Tests.ps1 b/src/Tests/Public/Add-CCMGroup.Tests.ps1
new file mode 100644
index 0000000..883a673
--- /dev/null
+++ b/src/Tests/Public/Add-CCMGroup.Tests.ps1
@@ -0,0 +1,414 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Add-CCMGroup" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMComputer -ModuleName ChocoCCM {
+            1..10 | ForEach-Object {
+                @{
+                    name = "Computer $_"
+                    id   = $_
+                }
+            }
+        }
+        Mock Get-CCMGroup -ModuleName ChocoCCM {
+            1..10 | ForEach-Object {
+                @{
+                    name = "Group $_"
+                    id   = $_
+                }
+            }
+        }
+    }
+
+    Context "Adding a new group with no members" {
+        BeforeAll {
+            $TestParams = @{
+                Name        = "$(New-Guid)"
+                Description = "$(New-Guid)"
+                # Group     = @()
+                # Computer  = @()
+            }
+
+            $Result = Add-CCMGroup @TestParams
+        }
+
+        It "Calls the API to create the new group with no members" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Name -eq $TestParams.Name -and
+                $Body.Description -eq $TestParams.Description -and
+                $Body.Groups.Count -eq 0 -and
+                $Body.Computers.Count -eq 0
+            }
+        }
+
+        It "Returns the new group" {
+            $Result | Should -BeOfType [PSCustomObject]
+            $Result.name | Should -Be $TestParams.Name
+            $Result.description | Should -Be $TestParams.Description
+            $Result.groups | Should -Be $TestParams.Group
+            $Result.computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Adding a new group containing a computer" {
+        BeforeAll {
+            $TestParams = @{
+                Name        = "$(New-Guid)"
+                Description = "$(New-Guid)"
+                # Group     = @()
+                Computer    = "Computer $(Get-Random -Minimum 1 -Maximum 10)"
+            }
+
+            $Result = Add-CCMGroup @TestParams
+        }
+
+        It "Calls the API to create the new group with the computer" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Name -eq $TestParams.Name -and
+                $Body.Description -eq $TestParams.Description -and
+                $Body.Groups.Count -eq 0 -and
+                $Body.Computers.computerId -eq $TestParams.Computer.Split(' ')[-1]
+            }
+        }
+
+        It "Returns the new group" {
+            $Result | Should -BeOfType [PSCustomObject]
+            $Result.name | Should -Be $TestParams.Name
+            $Result.description | Should -Be $TestParams.Description
+            $Result.groups | Should -Be $TestParams.Group
+            $Result.computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    # Containing multiple computers
+    Context "Adding a new group containing multiple computers" {
+        BeforeAll {
+            $TestParams = @{
+                Name        = "$(New-Guid)"
+                Description = "$(New-Guid)"
+                # Group     = @()
+                Computer    = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { "Computer $_" }
+            }
+
+            $Result = Add-CCMGroup @TestParams
+        }
+
+        It "Calls the API to create the new group with the computers" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Name -eq $TestParams.Name -and
+                $Body.Description -eq $TestParams.Description -and
+                $Body.Groups.Count -eq 0 -and
+                $Body.Computers.computerId -eq $TestParams.Computer.Split(' ')[-1]
+
+                $script:ResultComputers = $Body.Computers
+            }
+
+            $script:ResultComputers | Should -HaveCount $TestParams.Computer.Count
+        }
+
+        It "Returns the new group" {
+            $Result | Should -BeOfType [PSCustomObject]
+            $Result.name | Should -Be $TestParams.Name
+            $Result.description | Should -Be $TestParams.Description
+            $Result.groups | Should -Be $TestParams.Group
+            $Result.computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Adding a new group containing another group" {
+        BeforeAll {
+            $TestParams = @{
+                Name        = "$(New-Guid)"
+                Description = "$(New-Guid)"
+                Group       = "Group $(Get-Random -Minimum 1 -Maximum 10)"
+            }
+
+            $Result = Add-CCMGroup @TestParams
+        }
+
+        It "Calls the API to create the new group with the computer" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Name -eq $TestParams.Name -and
+                $Body.Description -eq $TestParams.Description -and
+                $Body.Groups.subGroupId -eq $TestParams.Group.Split(' ')[-1] -and
+                $Body.Computers.Count -eq 0
+            }
+        }
+
+        It "Returns the new group" {
+            $Result | Should -BeOfType [PSCustomObject]
+            $Result.name | Should -Be $TestParams.Name
+            $Result.description | Should -Be $TestParams.Description
+            $Result.groups | Should -Be $TestParams.Group
+            $Result.computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Adding a new group containing multiple groups" {
+        BeforeAll {
+            $TestParams = @{
+                Name        = "$(New-Guid)"
+                Description = "$(New-Guid)"
+                Group       = 1..10 | Get-Random -Count (Get-Random -Minimum 2 -Maximum 10) | ForEach-Object { "Group $_" }
+            }
+
+            $Result = Add-CCMGroup @TestParams
+        }
+
+        It "Calls the API to create the new group with the computer" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Name -eq $TestParams.Name -and
+                $Body.Description -eq $TestParams.Description -and
+                $Body.Groups.subGroupId -eq $TestParams.Group.Split(' ')[-1] -and
+                $Body.Computers.Count -eq 0
+            }
+        }
+
+        It "Returns the new group" {
+            $Result | Should -BeOfType [PSCustomObject]
+            $Result.name | Should -Be $TestParams.Name
+            $Result.description | Should -Be $TestParams.Description
+            $Result.groups | Should -Be $TestParams.Group
+            $Result.computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Adding a new group containing a group and a computer" {
+        BeforeAll {
+            $TestParams = @{
+                Name        = "$(New-Guid)"
+                Description = "$(New-Guid)"
+                Group       = "Group $(Get-Random -Minimum 1 -Maximum 10)"
+                Computer    = "Computer $(Get-Random -Minimum 1 -Maximum 10)"
+            }
+
+            $Result = Add-CCMGroup @TestParams
+        }
+
+        It "Calls the API to create the new group with the computer" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Name -eq $TestParams.Name -and
+                $Body.Description -eq $TestParams.Description -and
+                $Body.Groups.subGroupId -eq $TestParams.Group.Split(' ')[-1] -and
+                $Body.Computers.computerId -eq $TestParams.Computer.Split(' ')[-1]
+            }
+        }
+
+        It "Returns the new group" {
+            $Result | Should -BeOfType [PSCustomObject]
+            $Result.name | Should -Be $TestParams.Name
+            $Result.description | Should -Be $TestParams.Description
+            $Result.groups | Should -Be $TestParams.Group
+            $Result.computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Adding a new group containing a group and multiple computers" {
+        BeforeAll {
+            $TestParams = @{
+                Name        = "$(New-Guid)"
+                Description = "$(New-Guid)"
+                Group       = "Group $(Get-Random -Minimum 1 -Maximum 10)"
+                Computer    = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { "Computer $_" }
+            }
+
+            $Result = Add-CCMGroup @TestParams
+        }
+
+        It "Calls the API to create the new group with the computer" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Name -eq $TestParams.Name -and
+                $Body.Description -eq $TestParams.Description -and
+                $Body.Groups.subGroupId -eq $TestParams.Group.Split(' ')[-1] -and
+                $Body.Computers.computerId -eq $TestParams.Computer.Split(' ')[-1]
+            }
+        }
+
+        It "Returns the new group" {
+            $Result | Should -BeOfType [PSCustomObject]
+            $Result.name | Should -Be $TestParams.Name
+            $Result.description | Should -Be $TestParams.Description
+            $Result.groups | Should -Be $TestParams.Group
+            $Result.computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Adding a new group containing multiple groups and a computer" {
+        BeforeAll {
+            $TestParams = @{
+                Name        = "$(New-Guid)"
+                Description = "$(New-Guid)"
+                Group       = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { "Group $_" }
+                Computer    = "Computer $(Get-Random -Minimum 1 -Maximum 10)"
+            }
+
+            $Result = Add-CCMGroup @TestParams
+        }
+
+        It "Calls the API to create the new group with the computer" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Name -eq $TestParams.Name -and
+                $Body.Description -eq $TestParams.Description -and
+                $Body.Groups.subGroupId -eq $TestParams.Group.Split(' ')[-1] -and
+                $Body.Computers.computerId -eq $TestParams.Computer.Split(' ')[-1]
+            }
+        }
+
+        It "Returns the new group" {
+            $Result | Should -BeOfType [PSCustomObject]
+            $Result.name | Should -Be $TestParams.Name
+            $Result.description | Should -Be $TestParams.Description
+            $Result.groups | Should -Be $TestParams.Group
+            $Result.computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Adding a new group containing multiple groups and multiple computers" {
+        BeforeAll {
+            $TestParams = @{
+                Name        = "$(New-Guid)"
+                Description = "$(New-Guid)"
+                Group       = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { "Group $_" }
+                Computer    = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { "Computer $_" }
+            }
+
+            $Result = Add-CCMGroup @TestParams
+        }
+
+        It "Calls the API to create the new group with the computer" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Name -eq $TestParams.Name -and
+                $Body.Description -eq $TestParams.Description -and
+                $Body.Groups.subGroupId -eq $TestParams.Group.Split(' ')[-1] -and
+                $Body.Computers.computerId -eq $TestParams.Computer.Split(' ')[-1]
+            }
+        }
+
+        It "Returns the new group" {
+            $Result | Should -BeOfType [PSCustomObject]
+            $Result.name | Should -Be $TestParams.Name
+            $Result.description | Should -Be $TestParams.Description
+            $Result.groups | Should -Be $TestParams.Group
+            $Result.computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    # Creating an already existing group name
+    Context "Adding a new group with an already existing name" -Skip {
+        # This is apparently fine to do. Hmph.
+        # Given the way it's written (e.g. using $Current to update the object?),
+        # I can't tell if this is good or bad. It seems to be modelled on Add-CCMGroupMember... sort of.
+    }
+
+    Context "Failing to create a group" {
+        BeforeAll {
+            Mock Invoke-RestMethod -ModuleName ChocoCCM {
+                throw "A server error occurred"
+            }
+
+            $TestParams = @{
+                Name        = "$(New-Guid)"
+                Description = "$(New-Guid)"
+            }
+        }
+
+        It "Surfaces the error" {
+            { $Result = Add-CCMGroup @TestParams } | Should -Throw
+        }
+
+        It "Calls the API to create the new group with no members" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Name -eq $TestParams.Name -and
+                $Body.Description -eq $TestParams.Description -and
+                $Body.Groups.Count -eq 0 -and
+                $Body.Computers.Count -eq 0
+            }
+        }
+
+        It "Returns nothing." {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    # Creating a group containing non-existent computers
+    # Similarly, this won't complain. Maybe it should?
+
+    # Creating a group containing non-existent groups
+    # Similarly, this won't complain. Maybe it should?
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Add-CCMGroupMember.Tests.ps1 b/src/Tests/Public/Add-CCMGroupMember.Tests.ps1
new file mode 100644
index 0000000..86d6086
--- /dev/null
+++ b/src/Tests/Public/Add-CCMGroupMember.Tests.ps1
@@ -0,0 +1,420 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Add-CCMGroupMember" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Get-CCMComputer -ModuleName ChocoCCM {
+            1..10 | ForEach-Object {
+                @{
+                    name       = "Computer $_"
+                    id         = $_
+                    computerId = $_
+                }
+            }
+        }
+        Mock Get-CCMGroup -ModuleName ChocoCCM {
+            1..10 | ForEach-Object {
+                @{
+                    name = "Group $_"
+                    id   = $_
+                }
+            }
+        }
+        Mock Get-CCMGroupMember -ModuleName ChocoCCM {
+            [pscustomobject]@{
+                Id          = "$(New-Guid)"
+                Name        = $Group
+                Description = "Definitely a real group"
+                Groups      = $script:ExistingMemberGroups
+                Computers   = $script:ExistingMemberComputers
+                CanDeploy   = $true
+            }
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit"
+        } {
+            if ($Body -is [string]) {
+                $Body = $Body | ConvertFrom-Json
+            }
+
+            $Body.Computers.ForEach{
+                if ($script:ExistingMemberComputers.computerId -notcontains $_.computerId) {
+                    $script:ExistingMemberComputers += @{ computerId = $_.computerId ; computerName = "Computer $($_.computerId)" }
+                }
+            }
+            $Body.Groups.ForEach{
+                if ($script:ExistingMemberGroups.subGroupId -notcontains $_.subGroupId) {
+                    $script:ExistingMemberGroups += @{ subGroupId = $_.subGroupId ; subGroupName = "Group $($_.subGroupId)" }
+                }
+            }
+        }
+
+    }
+
+    Context "Adding a computer to an existing group" {
+        BeforeAll {
+            $script:ExistingMemberGroups = @()
+            $script:ExistingMemberComputers = @()  # No existing members
+
+            $TestParams = @{
+                Name     = "$(New-Guid)"
+                Computer = @("Computer $(Get-Random -Minimum 1 -Maximum 10)")
+            }
+
+            $Result = Add-CCMGroupMember @TestParams
+        }
+
+        It "Calls the API to add group members" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Computers.computerId -eq $TestParams.Computer.Split(' ')[-1] -and
+                $Body.Groups.Count -eq 0
+            }
+        }
+
+        It "Returns the updated group" {
+            $Result | Should -BeOfType [PSCustomObject]
+
+            $Result.Name | Should -Be $TestParams.Name
+            $Result.Computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Adding multiple computers to an existing group" {
+        BeforeAll {
+            $script:ExistingMemberGroups = @()
+            $script:ExistingMemberComputers = @()  # No existing members
+
+            $TestParams = @{
+                Name     = "$(New-Guid)"
+                Computer = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { "Computer $_" }
+            }
+
+            $Result = Add-CCMGroupMember @TestParams
+        }
+
+        It "Calls the API to add group members" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Computers.computerId -eq $TestParams.Computer.Split(' ')[-1] -and
+                $Body.Groups.Count -eq 0
+            }
+        }
+
+        It "Returns the updated group" {
+            $Result | Should -BeOfType [PSCustomObject]
+
+            $Result.Name | Should -Be $TestParams.Name
+            $Result.Computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Adding a group to an existing group" {
+        BeforeAll {
+            $script:ExistingMemberGroups = @()  # No existing members
+            $script:ExistingMemberComputers = @()
+
+            $TestParams = @{
+                Name  = "$(New-Guid)"
+                Group = "Group $(Get-Random -Minimum 1 -Maximum 10)"
+            }
+
+            $Result = Add-CCMGroupMember @TestParams
+        }
+
+        It "Calls the API to add group members" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Groups.subGroupId -eq $TestParams.Group.Split(' ')[-1] -and
+                $Body.Computers.Count -eq 0
+            }
+        }
+
+        It "Returns the updated group" {
+            $Result | Should -BeOfType [PSCustomObject]
+
+            $Result.Name | Should -Be $TestParams.Name
+            $Result.Groups | Should -Be $TestParams.Group
+        }
+    }
+
+    Context "Adding multiple groups to an existing group" {
+        BeforeAll {
+            $script:ExistingMemberGroups = @()  # No existing members
+            $script:ExistingMemberComputers = @()
+
+            $TestParams = @{
+                Name  = "$(New-Guid)"
+                Group = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { "Group $_" }
+            }
+
+            $Result = Add-CCMGroupMember @TestParams
+        }
+
+        It "Calls the API to add group members" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Groups.subGroupId -eq $TestParams.Group.Split(' ')[-1] -and
+                $Body.Computers.Count -eq 0
+            }
+        }
+
+        It "Returns the updated group" {
+            $Result | Should -BeOfType [PSCustomObject]
+
+            $Result.Name | Should -Be $TestParams.Name
+            $Result.Groups | Should -Be $TestParams.Group
+        }
+    }
+
+    Context "Adding multiple computers and groups to an existing group" {
+        BeforeAll {
+            $script:ExistingMemberGroups = @()  # No existing members
+            $script:ExistingMemberComputers = @()  # No existing members
+
+            $TestParams = @{
+                Name     = "$(New-Guid)"
+                Computer = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { "Computer $_" }
+                Group    = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { "Group $_" }
+            }
+
+            $Result = Add-CCMGroupMember @TestParams
+        }
+
+        It "Calls the API to add group members" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Groups.subGroupId -eq $TestParams.Group.Split(' ')[-1] -and
+                $Body.Computers.computerId -eq $TestParams.Computer.Split(' ')[-1]
+            }
+        }
+
+        It "Returns the updated group" {
+            $Result | Should -BeOfType [PSCustomObject]
+
+            $Result.Name | Should -Be $TestParams.Name
+            $Result.Groups | Should -Be $TestParams.Group
+            $Result.Computers | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Adding members that are already present in the group" {
+        BeforeAll {
+            $script:ExistingMemberGroups = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { @{ subGroupId = $_ ; subGroupName = "Group $($_)" } }
+            $script:ExistingMemberComputers = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { @{ computerId = $_ ; computerName = "Computer $($_)" } }
+
+            $TestParams = @{
+                Name     = "$(New-Guid)"
+                Computer = $script:ExistingMemberComputers.computerName
+                Group    = $script:ExistingMemberGroups.subGroupName
+            }
+
+            $Result = Add-CCMGroupMember @TestParams
+        }
+
+        It "Calls the API to add group members" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+                Write-Host $Body.Groups
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Groups.Count -eq 0 -and
+                ($Body.Computers.computerId | Sort-Object) -eq ($TestParams.Computer.Split(' ')[-1] | Sort-Object)
+            }
+        }
+
+        It "Returns the updated group" {
+            $Result | Should -BeOfType [PSCustomObject]
+
+            $Result.Name | Should -Be $TestParams.Name
+            $Result.Groups | Should -Be $script:ExistingMemberGroups.subGroupName
+            $Result.Computers | Should -Be $script:ExistingMemberComputers.computerName
+        }
+    }
+
+    Context "Adding a non-existent computer to a group" {
+        BeforeAll {
+            $script:ExistingMemberGroups = @()
+            $script:ExistingMemberComputers = @(1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { @{ computerId = $_ ; computerName = "Computer $($_)" } })
+
+            $TestParams = @{
+                Name     = "$(New-Guid)"
+                Computer = @("Saturn")
+            }
+
+            $Result = Add-CCMGroupMember @TestParams -WarningVariable "StoredWarning"
+        }
+
+        It "Warns that the computer doesn't exist and it's not being added" {
+            # Not a great test, but it will mean that if someone is relying on this message and we change it, we'll have to consider it.
+            $StoredWarning | Should -Be "A computer with the name $($TestParams.Computer) could not be found, skipping adding it to the group"
+        }
+
+        It "Calls the API to add group members without including the non-existent computer" {
+            # It's possible that if nothing changes, this shouldn't be called - but that's somewhat confused by us passing existing computers and not existing groups.
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Computers.Count -eq $script:ExistingMemberComputers.Count -and # This should not have increased.
+                $Body.Groups.Count -eq 0
+            }
+        }
+
+        It "Returns the updated group" {
+            $Result | Should -BeOfType [PSCustomObject]
+
+            $Result.Name | Should -Be $TestParams.Name
+            $Result.Computers | Should -Be $script:ExistingMemberComputers.computerName
+        }
+    }
+
+    Context "Adding a non-existent group to a group" {
+        BeforeAll {
+            $script:ExistingMemberGroups = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { @{ subGroupId = $_ ; subGroupName = "Group $($_)" } }
+            $script:ExistingMemberComputers = @()
+
+            $TestParams = @{
+                Name  = "$(New-Guid)"
+                Group = @("Solar System")
+            }
+
+            $Result = Add-CCMGroupMember @TestParams -WarningVariable "StoredWarning"
+        }
+
+        It "Warns that the computer doesn't exist and it's not being added" {
+            # Not a great test, but it will mean that if someone is relying on this message and we change it, we'll have to consider it.
+            $StoredWarning | Should -Be "A group with the name $($TestParams.Group) could not be found, skipping adding it to the group"
+        }
+
+        It "Calls the API to add group members without including the non-existent group" {
+            # It's possible that if nothing changes, this shouldn't be called - but that's somewhat confused by us passing existing computers and not existing groups.
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                Write-Host $Body
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Groups.Count -eq 0 -and # Groups do not get passed back, even if they already are there. See the comment above!
+                $Body.Computers.Count -eq 0
+
+                Write-Host "$($Body.Groups.Count)" "$($script:ExistingMemberGroups.Count)"
+            }
+        }
+
+        It "Returns the updated group" {
+            $Result | Should -BeOfType [PSCustomObject]
+
+            $Result.Name | Should -Be $TestParams.Name
+            $Result.Computers | Should -Be $script:ExistingMemberComputers.computerName
+        }
+    }
+
+    Context "Adding members to a group that doesn't exist" {
+        BeforeAll {
+            Mock Get-CCMGroupMember -ModuleName ChocoCCM {
+                throw [Microsoft.PowerShell.Commands.HttpResponseException]::new("Response status code does not indicate success: 400 (Bad Request).")
+            }
+
+            $TestParams = @{
+                Name     = "$(New-Guid)"
+                Computer = "Some Computer"
+            }
+        }
+
+        # This may be a terrible test.
+        It "Throws an error when the group doesn't exist." {
+            {Add-CCMGroupMember @TestParams} | Should -Throw
+        }
+    }
+
+    # Skipping: This needs thought, as it currently just responds with handy content for the PWD
+    Context "Completing Parameter Arguments" -Skip {
+        BeforeAll {
+            Mock Get-CCMGroup -ModuleName ChocoCCM {
+                "Alpha", "Bravo", "Charlie", "Delta" | ForEach-Object {
+                    @{ Name = $_ }
+                }
+            }
+        }
+
+        It "Has an argument completer for Name that lists all group names by default" {
+            $Command = "Add-CCMGroupMember -Name ''"
+            $Completions = [System.Management.Automation.CommandCompletion]::CompleteInput($Command, $Command.Length, $null)
+
+            $Completions.CompletionMatches.CompletionText | Should -HaveCount 4
+        }
+
+        It "Has an argument completer for Name that filters group names by entered text" {
+            $Command = "Add-CCMGroupMember -Name 'Alph'"
+            $Completions = [System.Management.Automation.CommandCompletion]::CompleteInput($Command, $Command.Length, $null)
+
+            $Completions.CompletionMatches.CompletionText | Should -HaveCount 1
+            $Completions.CompletionMatches.CompletionText | Should -Be "Alpha"
+        }
+    }
+
+    Context "Failing to add a group member" {
+        BeforeAll {
+            Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit"
+            } {
+                throw [Microsoft.PowerShell.Commands.HttpResponseException]::new("Response status code does not indicate success: 400 (Bad Request).")
+            }
+
+            $TestParams = @{
+                Name  = "$(New-Guid)"
+                Group = "Group $(Get-Random -Minimum 1 -Maximum 10)"
+            }
+        }
+
+        It "Throws an error when the group doesn't exist." {
+            {Add-CCMGroupMember @TestParams} | Should -Throw
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Connect-CCMServer.Tests.ps1 b/src/Tests/Public/Connect-CCMServer.Tests.ps1
new file mode 100644
index 0000000..b3fb1ea
--- /dev/null
+++ b/src/Tests/Public/Connect-CCMServer.Tests.ps1
@@ -0,0 +1,93 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Connect-CCMServer" {
+    BeforeAll {
+        Mock Invoke-WebRequest -ModuleName ChocoCCM -MockWith {
+            if ($SessionVariable -eq "Session") {
+                $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            }
+        }
+    }
+
+    Context "Logging into a HTTP Host" {
+        BeforeAll {
+            $TestValues = @{
+                Hostname   = "New-Guid"
+                Credential = [pscredential]::new(
+                    "$(New-Guid)",
+                    ("$(New-Guid)" | ConvertTo-SecureString -AsPlainText -Force)
+                )
+                UseSSL     = $false
+            }
+            $Result = Connect-CCMServer @TestValues
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+
+        It "Called /Account/Login using the provided Credentials" {
+            Should -Invoke Invoke-WebRequest -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "POST" -and
+                $Uri -eq "http://$($TestValues.Hostname)/Account/Login" -and
+                $ContentType -eq "application/x-www-form-urlencoded" -and
+                $Body.usernameOrEmailAddress -eq $TestValues.Credential.UserName -and
+                $Body.password -eq $TestValues.Credential.GetNetworkCredential().Password
+            }
+        }
+
+        It "Sets the Protocol Variable" {
+            InModuleScope ChocoCCM { $script:Protocol } | Should -Be "http"
+        }
+
+        It "Sets the Session Variable" -Skip {
+            # TODO: Fix this test.
+            InModuleScope ChocoCCM { $script:Session } | Should -Not -BeNullOrEmpty
+        }
+
+        It "Sets the Hostname Variable" {
+            InModuleScope ChocoCCM { $script:Hostname } | Should -Be $TestValues.Hostname
+        }
+    }
+
+    Context "Logging into a HTTPS Host" {
+        BeforeAll {
+            $TestValues = @{
+                Hostname   = "New-Guid"
+                Credential = [pscredential]::new(
+                    "$(New-Guid)",
+                    ("$(New-Guid)" | ConvertTo-SecureString -AsPlainText -Force)
+                )
+                UseSSL     = $true
+            }
+            $Result = Connect-CCMServer @TestValues
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+
+        It "Called /Account/Login using the provided Credentials" {
+            Should -Invoke Invoke-WebRequest -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "POST" -and
+                $Uri -eq "https://$($TestValues.Hostname)/Account/Login" -and
+                $ContentType -eq "application/x-www-form-urlencoded" -and
+                $Body.usernameOrEmailAddress -eq $TestValues.Credential.UserName -and
+                $Body.password -eq $TestValues.Credential.GetNetworkCredential().Password
+            }
+        }
+
+        It "Sets the Protocol Variable" {
+            InModuleScope ChocoCCM { $script:Protocol } | Should -Be "https"
+        }
+
+        It "Sets the Session Variable" -Skip {
+            # TODO: Fix this test.
+            InModuleScope ChocoCCM { $script:Session } | Should -Not -BeNullOrEmpty
+        }
+
+        It "Sets the Hostname Variable" {
+            InModuleScope ChocoCCM { $script:Hostname } | Should -Be $TestValues.Hostname
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Disable-CCMDeployment.Tests.ps1 b/src/Tests/Public/Disable-CCMDeployment.Tests.ps1
new file mode 100644
index 0000000..b7544f3
--- /dev/null
+++ b/src/Tests/Public/Disable-CCMDeployment.Tests.ps1
@@ -0,0 +1,70 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Disable-CCMDeployment" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Get-CCMDeployment -ModuleName ChocoCCM {
+            @{Id = $script:TestGuid}
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+    }
+
+    Context "Disabling a deployment" {
+        BeforeAll {
+            $script:TestGuid = "$(New-Guid)"
+            $TestParams = @{
+                Deployment = "Your Deployment"
+            }
+
+            $Result = Disable-CCMDeployment @TestParams -Confirm:$false
+        }
+
+        It "Calls the API to disable the deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/Archive" -and
+                $ContentType -eq "application/json" -and
+                $Body.id -eq $script:TestGuid
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Disabling a non-existent deployment" -Skip {
+        BeforeAll {
+            Mock Get-CCMDeployment -ModuleName ChocoCCM {
+                throw [Microsoft.PowerShell.Commands.HttpResponseException]::new("Response status code does not indicate success: 400 (Bad Request).")
+            }
+            Mock Invoke-RestMethod -ModuleName ChocoCCM {
+                throw [System.Management.Automation.RuntimeException]::new("Response status code does not indicate success: 400 (Bad Request).")
+            }
+        }
+
+        It "Throws an error when the deployment doesn't exist" {
+            {Disable-CCMDeployment @TestParams -Confirm:$false} | Should -Throw
+        }
+    }
+
+    Context "Failing to disable a deployment" {
+        BeforeAll {
+            Mock Invoke-RestMethod -ModuleName ChocoCCM {
+                throw [System.Management.Automation.RuntimeException]::new("Response status code does not indicate success: 400 (Bad Request).")
+            }
+        }
+
+        It "Throws an error when the API call fails" {
+            {Disable-CCMDeployment @TestParams -Confirm:$false} | Should -Throw
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Export-CCMDeployment.Tests.ps1 b/src/Tests/Public/Export-CCMDeployment.Tests.ps1
new file mode 100644
index 0000000..4d02e4f
--- /dev/null
+++ b/src/Tests/Public/Export-CCMDeployment.Tests.ps1
@@ -0,0 +1,150 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Export-CCMDeployment" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Get-CCMDeployment -ModuleName ChocoCCM {
+            @{
+                Name            = $Name
+                Description     = "This is a deployment"
+                DeploymentSteps = @(
+                    @{
+                        Name        = "Step 1"
+                        Description = "This is a step"
+                        Type        = "Install"
+                        Package     = @{
+                            Name    = "7zip"
+                            Version = "19.00"
+                        }
+                    }
+                    @{
+                        Name        = "Step 2"
+                        Description = "This is a step"
+                        Type        = "Install"
+                        Package     = @{
+                            Name    = "Firefox"
+                            Version = "21.00"
+                        }
+                    }
+                )
+            }
+        }
+    }
+
+    Context "Exporting a Deployment" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment = "$(New-Guid)"
+                OutFile    = Join-Path $TestDrive "TestFile.xml"
+            }
+
+            $Result = Export-CCMDeployment @TestParams
+        }
+
+        It "Calls the API to get the content of the specified deployment" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq $TestParams.Deployment
+            }
+        }
+
+        It "Exports the content to the specified file" {
+            $TestParams.OutFile | Should -FileContentMatch "This is a deployment"
+            $TestParams.OutFile | Should -FileContentMatch $TestParams.Deployment
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Exporting Deployment Steps Only" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment          = "$(New-Guid)"
+                DeploymentStepsOnly = $true
+                OutFile             = Join-Path $TestDrive "TestFile.xml"
+            }
+
+            $Result = Export-CCMDeployment @TestParams
+        }
+
+        It "Calls the API to get the content of the specified deployment" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq $TestParams.Deployment
+            }
+        }
+
+        It "Exports the deployment steps to the specified file" {
+            $TestParams.OutFile | Should -Not -FileContentMatch "This is a deployment"
+            $TestParams.OutFile | Should -Not -FileContentMatch $TestParams.Deployment
+            $TestParams.OutFile | Should -FileContentMatch "This is a step"
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Exporting to an existing file" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment   = "$(New-Guid)"
+                OutFile      = Join-Path $TestDrive "TestFile.xml"
+                AllowClobber = $false
+            }
+
+            New-Item -Path $TestParams.OutFile -Value "This is an old deployment"
+
+            $Result = Export-CCMDeployment @TestParams
+        }
+
+        It "Calls the API to get the content of the specified deployment" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq $TestParams.Deployment
+            }
+        }
+
+        It "Does not overwrite the deployment steps in the specified file" -Skip {
+            # This currently fails because the file is overwritten regardless of the AllowClobber parameter
+            $TestParams.OutFile | Should -FileContentMatch "This is an old deployment"
+            $TestParams.OutFile | Should -Not -FileContentMatch "This is a deployment"
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Overwriting an existing file" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment   = "$(New-Guid)"
+                OutFile      = Join-Path $TestDrive "TestFile.xml"
+                AllowClobber = $true
+            }
+
+            New-Item -Path $TestParams.OutFile -Value "This is an old deployment"
+
+            $Result = Export-CCMDeployment @TestParams
+        }
+
+        It "Calls the API to get the content of the specified deployment" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq $TestParams.Deployment
+            }
+        }
+
+        It "Exports the deployment to the specified file" {
+            $TestParams.OutFile | Should -Not -FileContentMatch "This is an old deployment"
+            $TestParams.OutFile | Should -FileContentMatch "This is a deployment"
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Export-CCMDeploymentReport.Tests.ps1 b/src/Tests/Public/Export-CCMDeploymentReport.Tests.ps1
new file mode 100644
index 0000000..7a744f6
--- /dev/null
+++ b/src/Tests/Public/Export-CCMDeploymentReport.Tests.ps1
@@ -0,0 +1,134 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Export-CCMDeploymentReport" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath.StartsWith("/api/services/app/DeploymentPlans/GetDeploymentPlanDetailsTo")
+        } {
+            $Extension = @("xlsx", "pdf")[[int]($Uri.AbsolutePath.EndsWith("Pdf"))]
+            [pscustomobject]@{
+                result = @{
+                    fileName  = $Uri.Query.Split('=')[-1] + '.' + $Extension
+                    fileType  = $Extension
+                    fileToken = "$(New-Guid)"
+                }
+            }
+        }
+        Mock Get-CCMDeployment -ModuleName ChocoCCM {
+            [PSCustomObject]@{Name = $Deployment; Id = "$(New-Guid)"}
+        }
+    }
+
+    Context "Exporting a PDF Deployment Report" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment   = "Complex"
+                Type         = "PDF"
+                OutputFolder = $TestDrive
+            }
+
+            $Result = Export-CCMDeploymentReport @TestParams
+        }
+
+        It "Calls the API to get a file type, token, and name" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetDeploymentPlanDetailsToPdf" -and
+                $Method -eq "GET" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Downloads the file" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/File/DownloadTempFile" -and
+                $Method -eq "GET" -and
+                $ContentType -eq "PDF" -and
+                $OutFile
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Exporting an Excel Deployment Report" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment   = "Complex"
+                Type         = "Excel"
+                OutputFolder = $TestDrive
+            }
+
+            $Result = Export-CCMDeploymentReport @TestParams
+        }
+
+        It "Calls the API to get a file type, token, and name" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetDeploymentPlanDetailsToExcel" -and
+                $Method -eq "GET" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Downloads the file" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/File/DownloadTempFile" -and
+                $Method -eq "GET" -and
+                $ContentType -eq "xlsx" -and
+                $OutFile
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Failing to find a deployment plan" {
+        BeforeAll {
+            Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+                $Uri.AbsolutePath.StartsWith("/api/services/app/DeploymentPlans/GetDeploymentPlanDetailsTo")
+            } -MockWith {
+                throw [System.Net.WebException]::new("Report not found")
+            }
+
+            $TestParams = @{
+                Deployment   = "Not Found"
+                Type         = "Excel"
+                OutputFolder = $TestDrive
+            }
+        }
+
+        It "Throws an error" {
+            { Export-CCMDeploymentReport @TestParams } | Should -Throw
+        }
+    }
+
+    Context "Failing to export a deployment plan" {
+        BeforeAll {
+            Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+                -not $Uri.AbsolutePath.StartsWith("/api/services/app/DeploymentPlans/GetDeploymentPlanDetailsTo")
+            } -MockWith {
+                throw [System.Net.WebException]::new("File not found.")
+            }
+
+            $TestParams = @{
+                Deployment   = "Not Found"
+                Type         = "PDF"
+                OutputFolder = $TestDrive
+            }
+        }
+
+        # Skipping: Despite the block around this, we don't actually throw. We just output the error details.
+        It "Throws an error" -Skip {
+            { Export-CCMDeploymentReport @TestParams } | Should -Throw
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Export-CCMOutdatedSoftwareReport.Tests.ps1 b/src/Tests/Public/Export-CCMOutdatedSoftwareReport.Tests.ps1
new file mode 100644
index 0000000..541c697
--- /dev/null
+++ b/src/Tests/Public/Export-CCMOutdatedSoftwareReport.Tests.ps1
@@ -0,0 +1,132 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Export-CCMOutdatedSoftwareReport" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath.StartsWith("/api/services/app/OutdatedReports/GetOutdatedSoftwareTo")
+        } {
+            $Extension = @("xlsx", "pdf")[[int]($Uri.AbsolutePath.EndsWith("Pdf"))]
+            [pscustomobject]@{
+                result = @{
+                    fileName  = $Uri.Query.Split('=')[-1] + '.' + $Extension
+                    fileType  = $Extension
+                    fileToken = "$(New-Guid)"
+                }
+            }
+        }
+        Mock Get-CCMOutdatedSoftwareReport -ModuleName ChocoCCM
+    }
+
+    Context "Exporting a PDF Report" {
+        BeforeAll {
+            $TestParams = @{
+                Report       = "7/4/2020 6:44:40 PM"
+                Type         = "PDF"
+                OutputFolder = $TestDrive
+            }
+
+            $Result = Export-CCMOutdatedSoftwareReport @TestParams
+        }
+
+        It "Calls the API to get a file type, token, and name" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/OutdatedReports/GetOutdatedSoftwareToPdf" -and
+                $Method -eq "GET" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Calls the API to download the appropriate file" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/File/DownloadTempFile" -and
+                $Method -eq "GET" -and
+                $ContentType -eq "pdf" -and
+                $OutFile
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Exporting an Excel Report" {
+        BeforeAll {
+            $TestParams = @{
+                Report       = "7/4/2020 6:44:40 PM"
+                Type         = "Excel"
+                OutputFolder = $TestDrive
+            }
+
+            $Result = Export-CCMOutdatedSoftwareReport @TestParams
+        }
+
+        It "Calls the API to get a file type, token, and name" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/OutdatedReports/GetOutdatedSoftwareToExcel" -and
+                $Method -eq "GET" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Calls the API to download the appropriate file" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/File/DownloadTempFile" -and
+                $Method -eq "GET" -and
+                $ContentType -eq "xlsx" -and
+                $OutFile
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Failing to find an outdated report" {
+        BeforeAll {
+            Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+                $Uri.AbsolutePath.StartsWith("/api/services/app/OutdatedReports/GetOutdatedSoftwareTo")
+            } -MockWith {
+                throw [System.Net.WebException]::new("Report not found")
+            }
+
+            $TestParams = @{
+                Report       = "Not Found"
+                Type         = "Excel"
+                OutputFolder = $TestDrive
+            }
+        }
+
+        It "Throws an error" {
+            { Export-CCMOutdatedSoftwareReport @TestParams } | Should -Throw
+        }
+    }
+
+    Context "Failing to export an outdated report" {
+        BeforeAll {
+            Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+                -not $Uri.AbsolutePath.StartsWith("/api/services/app/OutdatedReports/GetOutdatedSoftwareTo")
+            } -MockWith {
+                throw [System.Net.WebException]::new("File not found.")
+            }
+
+            $TestParams = @{
+                Report       = "Not Found"
+                Type         = "Excel"
+                OutputFolder = $TestDrive
+            }
+        }
+
+        # Skipping: Despite the block around this, we don't actually throw. We just output the error details.
+        It "Throws an error" -Skip {
+            { Export-CCMOutdatedSoftwareReport @TestParams } | Should -Throw
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-CCMComputer.Tests.ps1 b/src/Tests/Public/Get-CCMComputer.Tests.ps1
new file mode 100644
index 0000000..675a065
--- /dev/null
+++ b/src/Tests/Public/Get-CCMComputer.Tests.ps1
@@ -0,0 +1,116 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-CCMComputer" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath -eq "/api/services/app/Computers/GetAll"
+        } {
+            @{
+                result =  1..9 | ForEach-Object {
+                    [PSCustomObject]@{
+                        name = "Computer $_"
+                    }
+                }
+            }
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath -eq "/api/services/app/Computers/GetComputerForEdit"
+        } {
+            @{
+                computerGuid = "$(New-Guid)"
+                name         = "Computer $($Uri.Query.Split('=')[-1])"
+                id           = $Uri.Query.Split('=')[-1]
+            }
+        }
+    }
+
+    Context "Getting all computers" {
+        BeforeAll {
+            $Result = Get-CCMComputer
+        }
+
+        It "Calls the API to get all computers" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Computers/GetAll"
+            }
+        }
+
+        It "Returns All Computers" {
+            $Result | Should -HaveCount 9
+        }
+    }
+
+    Context "Getting a computer by Name" {
+        BeforeAll {
+            $TestParams = @{
+                Computer = "Computer $(Get-Random -Minimum 1 -Maximum 10)"
+            }
+            $Result = Get-CCMComputer @TestParams
+        }
+
+        It "Calls the API to get all computers" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Computers/GetAll"
+            }
+        }
+
+        It "Returns the computer requested" {
+            $Result | Should -HaveCount 1
+            $Result.name | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Getting computers by Name" {
+        BeforeAll {
+            $TestParams = @{
+                # This test fails when Computer 1 and Computer 10 are both selected, due to the naive match
+                Computer = 1..9 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 9) | ForEach-Object { "Computer $($_)" }
+                # Computer = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object { "Computer $($_)" }
+            }
+            $Result = Get-CCMComputer @TestParams
+        }
+
+        It "Calls the API to get all computers" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Computers/GetAll"
+            }
+        }
+
+        It "Returns the computer requested" {
+            $Result | Should -HaveCount $TestParams.Computer.Count
+            $Result.name | Should -Be $TestParams.Computer
+        }
+    }
+
+    Context "Getting a computer by ID" {
+        BeforeAll {
+            $TestParams = @{
+                ID = Get-Random -Minimum 1 -Maximum 10
+            }
+            $Result = Get-CCMComputer @TestParams
+        }
+
+        It "Doesn't call the API to get all computers" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 0 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Computers/GetAll"
+            }
+        }
+
+        It "Calls the API to get the exact computer" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 0 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Computers/GetComputerForEdit" -and
+                $Uri.Query.EndsWith($TestParams.ID)
+            }
+        }
+
+        It "Returns the computer requested" {
+            $Result | Should -HaveCount 1
+            $Result.name | Should -Be "Computer $($TestParams.ID)"
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-CCMDeployment.Tests.ps1 b/src/Tests/Public/Get-CCMDeployment.Tests.ps1
new file mode 100644
index 0000000..3bc21e4
--- /dev/null
+++ b/src/Tests/Public/Get-CCMDeployment.Tests.ps1
@@ -0,0 +1,188 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-CCMDeployment" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetAll"
+        } -MockWith {
+            $result = @{
+                result = @()
+            }
+            $result.result += [PSCustomObject]@{
+                name           = "bob"
+                id             = 0
+                deploymentPlan = @{
+                    name = "planbob"
+                }
+            }
+            $result.result += 1..9 | ForEach-Object {
+                [PSCustomObject]@{
+                    name           = "Deployment $_"
+                    id             = $_
+                    deploymentPlan = @{
+                        name = "plan$_"
+                    }
+                }
+            }
+            $result
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetDeploymentPlanForEdit"
+        } -MockWith {
+            @{
+                result = @{
+                    name = "Deployment $($Uri.Query.Split("=")[-1])"
+                    id   = $Uri.Query.Split("=")[-1]
+                    deploymentPlan = @{
+                        name = "plan$($Uri.Query.Split("=")[-1])"
+                    }
+                }
+            }
+        }
+        Mock Get-CCMDeploymentStep -ModuleName ChocoCCM -MockWith {
+            @{content = $true}
+        }
+    }
+
+    Context "Getting all deployments" {
+        BeforeAll {
+            $Result = Get-CCMDeployment
+        }
+
+        It "Calls the API to get all deployments" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetAll"
+            }
+        }
+
+        It "Returns all deployments, including deploymentPlans" {
+            $Result | Should -HaveCount 10
+            $Result.deploymentPlan.deploymentSteps | Should -BeNullOrEmpty
+            $Result.deploymentPlan | Should -Not -BeNullOrEmpty
+        }
+    }
+
+    Context "Getting a deployment by name" {
+        BeforeAll {
+            $TestParams = @{
+                Name = "bob"
+            }
+
+            $Result = Get-CCMDeployment @TestParams
+        }
+
+        It "Calls the API to get all deployments" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetAll"
+            }
+        }
+
+        It "Calls the API to get the specific deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetDeploymentPlanForEdit" -and
+                $Uri.Query -eq "?Id=0"
+            }
+        }
+
+        It "Returns the correct deployment plan" {
+            $Result.name | Should -Be "plan0"
+            $Result.deploymentSteps | Should -BeNullOrEmpty
+            $Result | Should -HaveCount 1
+        }
+    }
+
+    Context "Getting a deployment by ID" {
+        BeforeAll {
+            $TestParams = @{
+                Id = Get-Random -Minimum 1 -Maximum 9
+            }
+
+            $Result = Get-CCMDeployment @TestParams
+        }
+
+        It "Does not call the API to get all deployments" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 0 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetAll"
+            }
+        }
+
+        It "Calls the API to get the specific deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetDeploymentPlanForEdit" -and
+                $Uri.Query -eq "?Id=$($TestParams.Id)"
+            }
+        }
+
+        It "Returns the correct deployment plan" {
+            $Result.name | Should -Be "plan$($TestParams.Id)"
+            $Result.deploymentSteps | Should -BeNullOrEmpty
+            $Result | Should -HaveCount 1
+        }
+    }
+
+    Context "Including Step Results with ID" {
+        BeforeAll {
+            $TestParams = @{
+                Id                 = Get-Random -Minimum 1 -Maximum 9
+                IncludeStepResults = $true
+            }
+
+            $Result = Get-CCMDeployment @TestParams
+        }
+
+        It "Does not call the API to get all deployments" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 0 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetAll"
+            }
+        }
+
+        It "Calls the API to get the specific deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetDeploymentPlanForEdit" -and
+                $Uri.Query -eq "?Id=$($TestParams.Id)"
+            }
+        }
+
+        It "Returns the correct deployment plan" {
+            $Result.name | Should -Be "plan$($TestParams.Id)"
+            $Result.deploymentSteps | Should -Not -BeNullOrEmpty
+            $Result | Should -HaveCount 1
+        }
+    }
+
+    Context "Including Step Results with Name" {
+        BeforeAll {
+            $TestParams = @{
+                Name               = "bob"
+                IncludeStepResults = $true
+            }
+
+            $Result = Get-CCMDeployment @TestParams
+        }
+
+        It "Calls the API to get all deployments" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetAll"
+            }
+        }
+
+        It "Calls the API to get the specific deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/GetDeploymentPlanForEdit" -and
+                $Uri.Query -eq "?Id=0"
+            }
+        }
+
+        It "Returns the correct deployment plan, including deployment steps" {
+            $Result.name | Should -Be "plan0"
+            $Result | Should -HaveCount 1
+            $Result.deploymentSteps | Should -Not -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-CCMDeploymentStep.Tests.ps1 b/src/Tests/Public/Get-CCMDeploymentStep.Tests.ps1
new file mode 100644
index 0000000..a3189be
--- /dev/null
+++ b/src/Tests/Public/Get-CCMDeploymentStep.Tests.ps1
@@ -0,0 +1,110 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-CCMDeploymentStep" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath.EndsWith("GetDeploymentStepForEdit")
+        } {
+            @{
+                name = "Deployment Step $($Body.Id)"
+                deploymentStepComputers = @{
+                    overwritten = $false
+                }
+            }
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath.EndsWith("GetAllByDeploymentStepId")
+        } {
+            @{
+                result = @{
+                    overwritten = $true
+                }
+            }
+        }
+    }
+
+    Context "Getting Deployment Steps by ID, including results" {
+        BeforeAll {
+            $TestParams = @{
+                ID             = "583"
+                IncludeResults = $true
+            }
+
+            $Result = Get-CCMDeploymentStep @TestParams
+        }
+
+        It "Calls the API to get the Deployment Step" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentSteps/GetDeploymentStepForEdit" -and
+                $Body.Id -eq $TestParams.ID
+            }
+        }
+
+        It "Returns the deployment step, overwriting the deploymentStepComputers results" {
+            $Result | Should -Not -BeNullOrEmpty
+            $Result.deploymentStepComputers.overwritten | Should -Be $true
+        }
+    }
+
+    Context "Getting Deployment Steps by InputObject, not including results" {
+        BeforeAll {
+            $TestParams = @{
+                InputObject    = @{id = "583"}
+                IncludeResults = $false
+            }
+
+            $Result = Get-CCMDeploymentStep @TestParams
+        }
+
+        It "Calls the API to get the Deployment Step" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentSteps/GetDeploymentStepForEdit" -and
+                $Body.Id -eq $TestParams.InputObject.Id
+            }
+        }
+
+        It "Returns the deployment step, overwriting the deploymentStepComputers results" {
+            $Result | Should -Not -BeNullOrEmpty
+            $Result.deploymentStepComputers.overwritten | Should -Be $false
+        }
+    }
+
+    Context "Getting Deployment Steps by pipelined input" {
+        BeforeAll {
+            $TestParams = [PSCustomObject]@{
+                ID = "583"
+            }
+
+            $Result = $TestParams | Get-CCMDeploymentStep
+        }
+
+        It "Calls the API to get the Deployment Step" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentSteps/GetDeploymentStepForEdit" -and
+                $Body.Id -eq $TestParams.ID
+            }
+        }
+
+        It "Returns the deployment step, overwriting the deploymentStepComputers results" {
+            $Result | Should -Not -BeNullOrEmpty
+            $Result.deploymentStepComputers.overwritten | Should -Be $false
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-CCMGroup.Tests.ps1 b/src/Tests/Public/Get-CCMGroup.Tests.ps1
new file mode 100644
index 0000000..c45ccfc
--- /dev/null
+++ b/src/Tests/Public/Get-CCMGroup.Tests.ps1
@@ -0,0 +1,165 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-CCMGroup" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath.EndsWith("GetAll")
+        } {
+            @{
+                result = 1..10 | ForEach-Object {
+                    @{
+                        id = $_
+                        name = "Group $_"
+                    }
+                }
+            }
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath.EndsWith("GetGroupForEdit")
+        } {
+            @{
+                result = @{
+                    id = $Uri.Query.Split('=')[1]
+                    name = "Group $($Uri.Query.Split('=')[1])"
+                }
+            }
+        }
+    }
+
+    Context "Getting all groups" {
+        BeforeAll {
+            $Result = Get-CCMGroup
+        }
+
+        It "Calls the API to get all groups" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/GetAll"
+            }
+        }
+
+        It "Returns all groups" {
+            $Result | Should -HaveCount 10
+        }
+    }
+
+    Context "Getting a group by ID" {
+        BeforeAll {
+            $TestParams = @{
+                Id = "1"
+            }
+
+            $Result = Get-CCMGroup @TestParams
+        }
+
+        It "Does not call the API to get all groups" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 0 -Exactly -ParameterFilter {
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/GetAll"
+            }
+        }
+
+        It "Calls the API to get the exact group requested" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/GetGroupForEdit" -and
+                $Uri.Query -eq "?Id=$($TestParams.Id)"
+            }
+        }
+
+        It "Returns the requested group" {
+            $Result | Should -HaveCount 1
+            $Result.Id | Should -Be $TestParams.Id
+            $Result.Name | Should -Be "Group $($TestParams.Id)"
+        }
+    }
+
+    Context "Getting a group by name" {
+        BeforeAll {
+            $TestParams = @{
+                Group = "Group $(Get-Random -Minimum 1 -Maximum 10)"
+            }
+
+            $Result = Get-CCMGroup @TestParams
+        }
+
+        It "Calls the API to get all groups" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/GetAll"
+            }
+        }
+
+        It "Returns the correct group" {
+            $Result.name | Should -Be $TestParams.Group
+        }
+    }
+
+    # These two appear to not work well, and should probably be rewritten or removed from the functionality
+    Context "Getting multiple groups by name" -Skip {
+        BeforeAll {
+            $TestParams = @{
+                Group = 1..10 | Get-Random -Count (Get-Random -Minimum 1 -Maximum 10) | ForEach-Object {"Group $($_)"} | Sort-Object {[int]($_.Split(' ')[-1])}
+            }
+
+            $Result = Get-CCMGroup @TestParams
+        }
+
+        It "Calls the API to get all groups" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/GetAll"
+            }
+        }
+
+        It "Returns the correct groups" {
+            $Result.Name | Sort-Object {[int]($_.Split(' ')[-1])} | Should -Be $TestParams.Group
+            $Results.Name | Should -HaveCount $TestParams.Group.Count
+        }
+    }
+
+
+    # Getting multiple groups by ID is very likely to fail badly, as there's no handling for [string[]]
+    Context "Getting multiple groups by ID" -Skip {
+        BeforeAll {
+            $TestParams = @{
+                Id = "1","2","3"
+            }
+
+            $Result = Get-CCMGroup @TestParams
+        }
+
+        It "Does not call the API to get all groups" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 0 -Exactly -ParameterFilter {
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/GetAll"
+            }
+        }
+
+        It "Calls the API to get the exact group requested once per group requested" {
+            foreach ($Id in $TestParams.Id) {
+                Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                    $Uri.AbsolutePath -eq "/api/services/app/Groups/GetGroupForEdit" -and
+                    $Uri.Query -eq "?Id=$($Id)"
+                }
+            }
+        }
+        
+        It "Should absolutely not call the API to get the exact group requested once with all the IDs concatenated" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 0 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/GetGroupForEdit" -and
+                $Uri.Query -eq "?Id=$($TestParams.Id -join '%20')"
+            }
+        }
+
+        It "Returns the requested group" {
+            $Result | Should -HaveCount $TestParams.Id.Count
+            $Result.Id | Should -Be $TestParams.Id
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-CCMGroupMember.Tests.ps1 b/src/Tests/Public/Get-CCMGroupMember.Tests.ps1
new file mode 100644
index 0000000..7aaad2b
--- /dev/null
+++ b/src/Tests/Public/Get-CCMGroupMember.Tests.ps1
@@ -0,0 +1,55 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-CCMGroupMember" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMGroup -ModuleName ChocoCCM {
+            @{
+                Id = if ($Id) {$Id} else {$Group.Split(' ')[-1]}
+                Name = if ($Group) {$Group} else {"Group $Id"}
+                Description = "A real group."
+                Groups = @("Groups")
+                Computers = @("Computers")
+                isEligibleForDeployments = "ValueOfIsEligibleForDeployments"
+            }
+        }
+    }
+
+    Context "Getting group membership" {
+        BeforeAll {
+            $TestParams = @{
+                Group = "Group 1"
+            }
+
+            $Result = Get-CCMGroupMember @TestParams
+        }
+
+        It "Calls Get-CCMGroup to get the group ID" {
+            Should -Invoke Get-CCMGroup -Module ChocoCCM -Scope Context -ParameterFilter {
+                $Group -eq $TestParams.Group
+            }
+        }
+
+        It "Calls Get-CCMGroup to get the group details based on the returned ID" {
+            Should -Invoke Get-CCMGroup -Module ChocoCCM -Scope Context -ParameterFilter {
+                $Id -eq $TestParams.Group.Split(' ')[-1]
+            }
+        }
+
+        It "Returns a new object containing information on the group membership" {
+            # This test is rubbish, but we want to show that if we break "the contract" (e.g. the keys returned not matching the API returns)
+            # then we need to be mindful that we are changing the output a customer _may_ expect, and have to adjust tests accordingly.
+            $Result.Id | Should -Be "1"
+            $Result.Name | Should -Be "Group 1"
+            $Result.Description | Should -Be "A real group."
+            $Result.Groups | Should -Be @( "Groups" )
+            $Result.Computers | Should -Be @( "Computers" )
+            $Result.CanDeploy | Should -Be "ValueOfIsEligibleForDeployments"
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-CCMOutdatedSoftware.Tests.ps1 b/src/Tests/Public/Get-CCMOutdatedSoftware.Tests.ps1
new file mode 100644
index 0000000..5ed6795
--- /dev/null
+++ b/src/Tests/Public/Get-CCMOutdatedSoftware.Tests.ps1
@@ -0,0 +1,47 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-CCMOutdatedSoftware" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Get-CCMSoftware -ModuleName ChocoCCM -MockWith {
+            @(
+                @{
+                    id = 1
+                    name = "Software 1"
+                    version = "1.0.0"
+                    isOutdated = $true
+                },
+                @{
+                    id = 2
+                    name = "Software 2"
+                    version = "1.0.0"
+                    isOutdated = $false
+                },
+                @{
+                    id = 3
+                    name = "Software 3"
+                    version = "1.0.0"
+                    isOutdated = $true
+                }
+            )
+        }
+    }
+
+    Context "Getting Outdated Software" {
+        BeforeAll {
+            $Result = Get-CCMOutdatedSoftware
+        }
+
+        It "Calls Get-CCMSoftware" {
+            Should -Invoke Get-CCMSoftware -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly
+        }
+
+        It "Returns only software where isOutdated is true" {
+            $Result.isOutdated | Should -Not -Contain $false
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-CCMOutdatedSoftwareMember.Tests.ps1 b/src/Tests/Public/Get-CCMOutdatedSoftwareMember.Tests.ps1
new file mode 100644
index 0000000..cc0d051
--- /dev/null
+++ b/src/Tests/Public/Get-CCMOutdatedSoftwareMember.Tests.ps1
@@ -0,0 +1,100 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-CCMOutdatedSoftwareMember" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMSoftware -ModuleName ChocoCCM -MockWith {
+            @(1..3 | ForEach-Object {@{softwareId = $_}})
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath -eq "/api/services/app/ComputerSoftware/GetAllPagedBySoftwareId"
+        } {
+            if ($Uri.Query -match "softwareId=(?<SoftwareId>\d+)") {
+                $SoftwareId = $Matches.SoftwareId
+            }
+            @{
+                result = @{
+                    items = foreach ($ComputerId in 1..4) {
+                        @{
+                            softwareId = $SoftwareId
+                            software   = @{
+                                name           = "VLC Media Player"
+                                packageId      = $SoftwareId
+                                packageVersion = "1.0.$($SoftwareId)"
+                            }
+                            computer   = @{
+                                name         = "Computer$($ComputerId)"
+                                friendlyName = "Computer $($ComputerId)"
+                                ipaddress    = "10.0.0.$($ComputerId)"
+                                fqdn         = "computer$($ComputerId).local"
+                                computerid   = "$(New-Guid)"
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    Context "Getting computers that have the specified software installed and requiring an update, using the software name" {
+        BeforeAll {
+            $TestParams = @{
+                Software = "VLC Media Player"
+            }
+
+            $Result = Get-CCMOutdatedSoftwareMember @TestParams
+        }
+
+        # It does seem that this will only ever get the first 100 results per piece of software
+        It "Calls the API to get computers with the specified software installed" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 3 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/ComputerSoftware/GetAllPagedBySoftwareId" -and
+                $Uri.Query -match "softwareId=(1|2|3)"
+            }
+        }
+
+        It "Returns a record per outdated-software-per-computer combination" {
+            $Result | Should -HaveCount 12
+        }
+    }
+
+    Context "Getting computers that have the specified software installed and requiring an update, using the package id" {
+        BeforeAll {
+            $TestParams = @{
+                Package = "vlc"
+            }
+
+            $Result = Get-CCMOutdatedSoftwareMember @TestParams
+        }
+
+        # It does seem that this will only ever get the first 100 results per piece of software
+        It "Calls the API to get computers with the specified software installed" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 3 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/ComputerSoftware/GetAllPagedBySoftwareId" -and
+                $Uri.Query -match "softwareId=(1|2|3)"
+            }
+        }
+
+        It "Returns a record per outdated-software-per-computer combination" {
+            $Result | Should -HaveCount 12
+        }
+    }
+
+    Context "Failing to return installs of the specified software" {
+        BeforeAll {
+            Mock Invoke-RestMethod -ModuleName ChocoCCM {
+                throw [System.Net.WebException]::new("Failed to get software")
+            }
+        }
+
+        # Skipping: Again, we are simply returning the exception message to output, polluting the output
+        It "Throws an exception" -Skip {
+            { Get-CCMOutdatedSoftwareMember -Software "vlc" } | Should -Throw
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-CCMOutdatedSoftwareReport.Tests.ps1 b/src/Tests/Public/Get-CCMOutdatedSoftwareReport.Tests.ps1
new file mode 100644
index 0000000..57d45c6
--- /dev/null
+++ b/src/Tests/Public/Get-CCMOutdatedSoftwareReport.Tests.ps1
@@ -0,0 +1,62 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-CCMOutdatedSoftwareReport" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath -eq "/api/services/app/Reports/GetAllPaged"
+        } {
+            @{
+                result = @{
+                    items = @(
+                        1..3 | ForEach-Object {
+                            @{
+                                reportType   = "OutdatedSoftware"
+                                creationTime = "$(Get-Date)"
+                                id           = "$(New-Guid)"
+                            }
+                        }
+                    )
+                }
+            }
+        }
+    }
+
+    Context "Getting an outdated report (that is actually up to date)" {
+        BeforeAll {
+            $Result = Get-CCMOutdatedSoftwareReport
+        }
+
+        It "Calls the API to get all existing reports" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Reports/GetAllPaged" -and
+                $Uri.Query -eq "?reportTypeFilter=1" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Returns all report objects" {
+            # Is this the correct behaviour? Check on ReportTypeFilter=1
+            $Result | Should -HaveCount 3
+        }
+    }
+
+    Context "Failing to get all reports" {
+        BeforeAll {
+            Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Reports/GetAllPaged"
+            } -MockWith {
+                throw [System.Net.WebException]::new("Failed")
+            }
+        }
+
+        It "Throws an exception when failing to get all reports" {
+            { Get-CCMOutdatedSoftwareReport } | Should -Throw "Failed"
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-CCMOutdatedSoftwareReportDetail.Tests.ps1 b/src/Tests/Public/Get-CCMOutdatedSoftwareReportDetail.Tests.ps1
new file mode 100644
index 0000000..55e4e8b
--- /dev/null
+++ b/src/Tests/Public/Get-CCMOutdatedSoftwareReportDetail.Tests.ps1
@@ -0,0 +1,56 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-CCMOutdatedSoftwareReportDetail" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMOutdatedSoftwareReport -ModuleName ChocoCCM {
+            @(
+                @{
+                    reportType   = "OutdatedSoftware"
+                    creationTime = "7/4/2020 6:44:40 PM"
+                    id           = $script:TestGuid
+                }
+                1..3 | ForEach-Object {
+                    @{
+                        reportType   = "OutdatedSoftware"
+                        creationTime = "$(Get-Date)"
+                        id           = "$(New-Guid)"
+                    }
+                }
+            )
+        }
+    }
+
+    Context "Getting a specific Outdated Software Report" {
+        BeforeAll {
+            $script:TestGuid = "$(New-Guid)"
+            $TestParams = @{
+                Report = "7/4/2020 6:44:40 PM"
+            }
+
+            $Result = Get-CCMOutdatedSoftwareReportDetail @TestParams
+        }
+
+        It "Calls Get-CCMOutdatedSoftwareReport to get the report ID" {
+            Should -Invoke Get-CCMOutdatedSoftwareReport -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly
+        }
+
+        It "Calls the API to get the report details" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/OutdatedReports/GetAllByReportId" -and
+                $Uri.Query -match "reportId=$($script:TestGuid)" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Returns the requested result" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-CCMRole.Tests.ps1 b/src/Tests/Public/Get-CCMRole.Tests.ps1
new file mode 100644
index 0000000..9f7a51b
--- /dev/null
+++ b/src/Tests/Public/Get-CCMRole.Tests.ps1
@@ -0,0 +1,104 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-CCMRole" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -MockWith {
+            @{
+                result = @{
+                    items = @(
+                        @{
+                            name = "CCMAdmin"
+                            id   = 1
+                        }
+                        @{
+                            name = "CCMUser"
+                            id   = 2
+                        }
+                    )
+                }
+            }
+        }
+    }
+
+    Context "Getting a specific CCM Role" {
+        BeforeAll {
+            $TestValues = @{
+                Name = "CCMAdmin"
+            }
+
+            $Result = Get-CCMRole @TestValues
+        }
+
+        It "Calls the API to get roles" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Role/GetRoles" -and
+                $Uri.Query -eq "?permission=" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Returns the correct role" {
+            $Result.Name | Should -Be $TestValues.Name
+            $Result | Should -HaveCount 1
+        }
+    }
+
+    Context "Getting a non-existent CCM Role" {
+        BeforeAll {
+            $TestValues = @{
+                Name = "OtherAdmin"
+            }
+
+            $Result = Get-CCMRole @TestValues
+        }
+
+        It "Calls the API to get roles" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Role/GetRoles" -and
+                $Uri.Query -eq "?permission=" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+    Context "Getting all CCM Roles" {
+        BeforeAll {
+            $Result = Get-CCMRole
+        }
+
+        It "Calls the API to get roles" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Role/GetRoles" -and
+                $Uri.Query -eq "?permission=" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Returns All Returned Roles" {
+            $Result | Should -HaveCount 2
+        }
+    }
+
+    Context "Failing to get a specified role" {
+        BeforeAll {
+            Mock Invoke-RestMethod -ModuleName ChocoCCM -MockWith {
+                throw [System.Net.WebException]::new("Failed")
+            }
+        }
+
+        It "Throws an exception when failing to get a specified role" {
+            { Get-CCMRole -Name "CCMBadmin" } | Should -Throw "Failed"
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-CCMSoftware.Tests.ps1 b/src/Tests/Public/Get-CCMSoftware.Tests.ps1
new file mode 100644
index 0000000..894932d
--- /dev/null
+++ b/src/Tests/Public/Get-CCMSoftware.Tests.ps1
@@ -0,0 +1,152 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-CCMSoftware" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath -eq "/api/services/app/Software/GetAll"
+        } {
+            @{
+                result = @{
+                    items = @(
+                        @{
+                            id        = 37
+                            name      = "VLC Media Player"
+                            packageId = "vlc"
+                        }
+                        @{
+                            id        = 38
+                            name      = "Mozilla Firefox"
+                            packageId = "mozillafirefox"
+                        }
+                    )
+                }
+            }
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath -eq "/api/services/app/ComputerSoftware/GetAllPagedBySoftwareId"
+        } {
+            @{
+                result = @(
+                    @{
+                        id        = 37
+                        name      = "VLC Media Player"
+                        packageId = "vlc"
+                    }
+                )
+            }
+        }
+    }
+
+    Context "Gets all software" {
+        BeforeAll {
+            $Result = Get-CCMSoftware
+        }
+
+        It "Calls the API to get all software IDs" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Software/GetAll"
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -HaveCount 2
+            $Result.name | Should -Contain "VLC Media Player"
+            $Result.name | Should -Contain "Mozilla Firefox"
+        }
+    }
+
+    Context "Gets software by name" {
+        BeforeAll {
+            $TestParams = @{
+                Software = "VLC Media Player"
+            }
+
+            $Result = Get-CCMSoftware @TestParams
+        }
+
+        It "Calls the API to get all software IDs" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Software/GetAll"
+            }
+        }
+
+        It "Calls the API to get the specific software ID" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/ComputerSoftware/GetAllPagedBySoftwareId" -and
+                $Uri.Query -match "softwareId=37"
+            }
+        }
+
+        It "Returns the VLC Software Details" {
+            $Result | Should -HaveCount 1
+            $Result.Name | Should -Be "VLC Media Player"
+            $Result.packageId | Should -Be "vlc"
+        }
+    }
+
+    Context "Gets software by package id" {
+        BeforeAll {
+            $TestParams = @{
+                Package = "vlc"
+            }
+
+            $Result = Get-CCMSoftware @TestParams
+        }
+
+        It "Calls the API to get all software IDs" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Software/GetAll"
+            }
+        }
+
+        It "Calls the API to get the specific software ID" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/ComputerSoftware/GetAllPagedBySoftwareId" -and
+                $Uri.Query -match "softwareId=37"
+            }
+        }
+
+        It "Returns the VLC Software Details" {
+            $Result | Should -HaveCount 1
+            $Result.Name | Should -Be "VLC Media Player"
+            $Result.packageId | Should -Be "vlc"
+        }
+    }
+
+    Context "Gets software by software id" {
+        BeforeAll {
+            $TestParams = @{
+                Id = "37"
+            }
+
+            $Result = Get-CCMSoftware @TestParams
+        }
+
+        It "Does not call the API to get all software IDs" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 0 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/Software/GetAll"
+            }
+        }
+
+        It "Calls the API to get the specific software ID" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Uri.AbsolutePath -eq "/api/services/app/ComputerSoftware/GetAllPagedBySoftwareId" -and
+                $Uri.Query -match "softwareId=37"
+            }
+        }
+
+        # Why is ID not expanding .items?
+        # Potential bug around items vs not items, given the same call in all cases.
+        It "Returns the VLC Software Details" -Skip {
+            $Result | Should -HaveCount 1
+            $Result.Name | Should -Be "VLC Media Player"
+            $Result.packageId | Should -Be "vlc"
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Get-DeploymentResult.Tests.ps1 b/src/Tests/Public/Get-DeploymentResult.Tests.ps1
new file mode 100644
index 0000000..64aa54a
--- /dev/null
+++ b/src/Tests/Public/Get-DeploymentResult.Tests.ps1
@@ -0,0 +1,58 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Get-DeploymentResult" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMDeployment -ModuleName ChocoCCM {
+            @{Id = 13}
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Uri.AbsolutePath -eq "/api/services/app/DeploymentSteps/GetAllPagedByDeploymentPlanId"
+        } {
+            @{
+                result = @{
+                    items = @(
+                        @{
+                            id = 13
+                            name = "Google Chrome Upgrade"
+                        }
+                    )
+                }
+            }
+        }
+    }
+
+    Context "Getting a deployment result" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment = "Google Chrome Upgrade"
+            }
+
+            $Result = Get-DeploymentResult @TestParams
+        }
+
+        It "Retrieves the deployment ID for the requested Deployment Name" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq $TestParams.Deployment
+            }
+        }
+
+        It "Calls the API to retrieve the deployment result based on the ID" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentSteps/GetAllPagedByDeploymentPlanId" -and
+                $ContentType -eq "application/json" -and
+                $Uri.Query -match "deploymentPlanId=13"
+            }
+        }
+
+        It "Returns the result items" {
+            $Result.name | Should -Be "Google Chrome Upgrade"
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Import-PDQDeployPackage.Tests.ps1 b/src/Tests/Public/Import-PDQDeployPackage.Tests.ps1
new file mode 100644
index 0000000..b1dfd3c
--- /dev/null
+++ b/src/Tests/Public/Import-PDQDeployPackage.Tests.ps1
@@ -0,0 +1,48 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Import-PDQDeployPackage" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock New-CCMDeployment -ModuleName ChocoCCM
+        Mock New-CCMDeploymentStep -ModuleName ChocoCCM
+    }
+
+    # Skipping: I need an example of the XML file.
+    Context "Importing an Example Package" -Skip {
+        BeforeAll {
+            New-Item -Path $TestDrive -Name "ExamplePackage.xml" -Value @"
+<xml></xml>
+"@
+            $TestParams = @{
+                PdqXml = "$TestDrive\ExamplePackage.xml"
+            }
+
+            $Result = Import-PDQDeployPackage @TestParams
+        }
+
+        It "Creates a new deployment with the name from the package" {
+            Should -Invoke New-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq "PDQ Import: Example Package"
+            }
+        }
+
+        It "Creates a step for each step within the PDQ Deployment" {
+            Should -Invoke New-CCMDeploymentStep -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Deployment -eq "PDQ Import: Example Package" -and
+                $Name -eq "Install Example Package" -and
+                $Type -eq "Basic" -and
+                $ValidExitCodes -eq @("0") -and
+                $FailOnError -eq $false
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Move-CCMDeploymentToReady.Tests.ps1 b/src/Tests/Public/Move-CCMDeploymentToReady.Tests.ps1
new file mode 100644
index 0000000..107fde8
--- /dev/null
+++ b/src/Tests/Public/Move-CCMDeploymentToReady.Tests.ps1
@@ -0,0 +1,65 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Move-CCMDeploymentToReady" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMDeployment -ModuleName ChocoCCM {
+            @{Id = $script:IdUnderTest}
+        }
+    }
+
+    Context "Moving a depoloyment to Ready" {
+        BeforeAll {
+            $script:IdUnderTest = Get-Random -Minimum 1 -Maximum 100
+            $TestParams = @{
+                Deployment = "Complex Deployment"
+            }
+
+            $Result = Move-CCMDeploymentToReady @TestParams
+        }
+
+        It "Retrieves the deployment ID for the requested Deployment Name" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq $TestParams.Deployment
+            }
+        }
+
+        It "Calls the API to move the returned ID to Ready" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/MoveToReady" -and
+                $ContentType -eq "application/json" -and
+                $Body.id -eq $script:IdUnderTest
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Failing to move a deployment step to ready" {
+        BeforeAll {
+            Mock Invoke-RestMethod -ModuleName ChocoCCM {
+                throw [webexception]::new("The remote server returned an error: (500) Internal Server Error.")
+            }
+
+            $TestParams = @{
+                Deployment = "Complex Deployment"
+            }
+        }
+
+        It "Throws an error when failing to move a deployment step to ready" {
+            { Move-CCMDeploymentToReady @TestParams } | Should -Throw
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/New-CCMDeployment.Tests.ps1 b/src/Tests/Public/New-CCMDeployment.Tests.ps1
new file mode 100644
index 0000000..ac2491c
--- /dev/null
+++ b/src/Tests/Public/New-CCMDeployment.Tests.ps1
@@ -0,0 +1,52 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "New-CCMDeployment" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Method -eq "POST" -and
+            $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/CreateOrEdit"
+        } {
+            @{
+                result = @{
+                    id = $script:GuidUnderTest
+                }
+            }
+        }
+    }
+
+    Context "Creating a new deployment" {
+        BeforeAll {
+            $script:GuidUnderTest = "$(New-Guid)"
+            $TestParams = @{
+                Name = "$(New-Guid)"
+            }
+
+            $Result = New-CCMDeployment @TestParams
+        }
+
+        It "Calls the API to create a new deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Name -eq $TestParams.Name
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result.name | Should -Be $TestParams.Name
+
+            # This should be returned by the request to DeploymentPlans/CreateOrEdit
+            $Result.id | Should -Be $script:GuidUnderTest
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/New-CCMDeploymentStep.Tests.ps1 b/src/Tests/Public/New-CCMDeploymentStep.Tests.ps1
new file mode 100644
index 0000000..de35a1c
--- /dev/null
+++ b/src/Tests/Public/New-CCMDeploymentStep.Tests.ps1
@@ -0,0 +1,136 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "New-CCMDeploymentStep" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMDeployment -ModuleName ChocoCCM {
+            @{Id = "ID:$Name"}
+        }
+        Mock Get-CCMGroup -ModuleName ChocoCCM {
+            foreach ($Group in $Group) {
+                @{
+                    Name = $Group
+                    Id = "ID:$Group"
+                }
+            }
+        }
+    }
+
+    Context "Creating a basic deployment step" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment   = "PowerShell"
+                Name         = "From ChocoCCM"
+                TargetGroup  = "WebServers"
+                Type         = "Basic"
+                ChocoCommand = "upgrade"
+                PackageName  = "firefox"
+            }
+
+            $Result = New-CCMDeploymentStep @TestParams
+        }
+
+        It "Calls the API to create the basic deployment step" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentSteps/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+
+                $Body.Name -eq $TestParams.Name -and
+                $Body.DeploymentPlanId -eq "ID:$($TestParams.Deployment)" -and
+                $Body.DeploymentStepGroups.groupname -eq $TestParams.TargetGroup -and
+                $Body.script -eq "$($TestParams.ChocoCommand.ToLower())|$($TestParams.PackageName)"
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Creating an advanced deployment step" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment  = "PowerShell"
+                Name        = "From ChocoCCM"
+                TargetGroup = "All", "PowerShell"
+                Type        = "Advanced"
+                Script      = {
+                    foreach ($p in Get-Process) {
+                        Write-Host $p.PID
+                    }
+                    Write-Host "end"
+                }
+            }
+
+            $Result = New-CCMDeploymentStep @TestParams
+        }
+
+        It "Calls the API to create the basic deployment step" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentSteps/CreateOrEditPrivileged" -and
+                $ContentType -eq "application/json" -and
+
+                $Body.Name -eq $TestParams.Name -and
+                $Body.DeploymentPlanId -eq "ID:$($TestParams.Deployment)" -and
+                "$($Body.DeploymentStepGroups.groupname)" -eq "$($TestParams.TargetGroup)" -and
+                $Body.script -eq $TestParams.Script.ToString()
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Creating an advanced deployment step from a file" {
+    # New-CCMDeploymentStep -Deployment PowerShell -Name 'From ChocoCCM' -TargetGroup All,PowerShell -Type Advanced -Script {(Get-Content C:\script.txt)}
+        BeforeAll {
+            New-Item $TestDrive\script.txt -ItemType File -Value 'foreach ($p in Get-Process) { Write-Host $p.PID } Write-Host "end"'
+            $TestParams = @{
+                Deployment  = "PowerShell"
+                Name        = "From ChocoCCM"
+                TargetGroup = "All", "PowerShell"
+                Type        = "Advanced"
+                Script      = { (Get-Content $TestDrive\script.txt) }
+            }
+
+            $Result = New-CCMDeploymentStep @TestParams
+        }
+
+        It "Calls the API to create the basic deployment step" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentSteps/CreateOrEditPrivileged" -and
+                $ContentType -eq "application/json" -and
+
+                $Body.Name -eq $TestParams.Name -and
+                $Body.DeploymentPlanId -eq "ID:$($TestParams.Deployment)" -and
+                "$($Body.DeploymentStepGroups.groupname)" -eq "$($TestParams.TargetGroup)" -and
+                $Body.script -eq $TestParams.Script.ToString()
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/New-CCMOutdatedSoftwareReport.Tests.ps1 b/src/Tests/Public/New-CCMOutdatedSoftwareReport.Tests.ps1
new file mode 100644
index 0000000..5ff469a
--- /dev/null
+++ b/src/Tests/Public/New-CCMOutdatedSoftwareReport.Tests.ps1
@@ -0,0 +1,30 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "New-CCMOutdatedSoftwareReport" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+    }
+
+    Context "Creating a new outdated software report" {
+        BeforeAll {
+            $Result = New-CCMOutdatedSoftwareReport
+        }
+
+        It "Calls the API to create a new outdated report" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/OutdatedReports/Create" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Remove-CCMDeployment.Tests.ps1 b/src/Tests/Public/Remove-CCMDeployment.Tests.ps1
new file mode 100644
index 0000000..301af36
--- /dev/null
+++ b/src/Tests/Public/Remove-CCMDeployment.Tests.ps1
@@ -0,0 +1,76 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Remove-CCMDeployment" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMDeployment -ModuleName ChocoCCM { @{Id = $script:IDUnderTest} }
+    }
+
+    Context "Removing a deployment" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment = "Super Complex Deployment"
+            }
+
+            $Result = Remove-CCMDeployment @TestParams -Confirm:$false
+        }
+
+        It "Gets the ID for the deployment to delete" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq $TestParams.Deployment
+            }
+        }
+
+        It "Calls the API to delete the deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "DELETE" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/Delete" -and
+                $Uri.Query -eq "?Id=$($script:IDUnderTest)" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Removing multiple deployments" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment = @(
+                    "Super Complex Deployment"
+                    "Deployment Alpha"
+                )
+            }
+
+            $Result = Remove-CCMDeployment @TestParams -Confirm:$false
+        }
+
+        It "Gets the ID for the deployment to delete" {
+            foreach ($Deployment in $TestParams.Deployment) {
+                Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                    $Name -eq $Deployment
+                }
+            }
+        }
+
+        It "Calls the API to delete each deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times $TestParams.Deployment.Count -Exactly -ParameterFilter {
+                $Method -eq "DELETE" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/Delete" -and
+                $Uri.Query -eq "?Id=$($script:IDUnderTest)" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Remove-CCMDeploymentStep.Tests.ps1 b/src/Tests/Public/Remove-CCMDeploymentStep.Tests.ps1
new file mode 100644
index 0000000..99231b5
--- /dev/null
+++ b/src/Tests/Public/Remove-CCMDeploymentStep.Tests.ps1
@@ -0,0 +1,51 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Remove-CCMDeploymentStep" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMDeployment -ModuleName ChocoCCM {
+            @{
+                Id              = "1"
+                deploymentSteps = @(
+                    @{
+                        id   = "2"
+                        Name = "Copy Files"
+                    }
+                    @{
+                        id   = "1"
+                        Name = "Kill web services"
+                    }
+                )
+            }
+        }
+    }
+
+    Context "Removing a deployment step" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment = "Deployment Alpha"
+                Step       = "Copy Files"
+            }
+
+            $Result = Remove-CCMDeploymentStep @TestParams -Confirm:$false
+        }
+
+        It "Calls the API to remove the deployment step" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "DELETE" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentSteps/Delete" -and
+                $Uri.Query -eq "?Id=2" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Remove-CCMGroup.Tests.ps1 b/src/Tests/Public/Remove-CCMGroup.Tests.ps1
new file mode 100644
index 0000000..1da7fa4
--- /dev/null
+++ b/src/Tests/Public/Remove-CCMGroup.Tests.ps1
@@ -0,0 +1,79 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Remove-CCMGroup" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMGroup -ModuleName ChocoCCM {
+            @{
+                Id = "$($Group)ID"
+            }
+        }
+    }
+
+    Context "Removing a group" {
+        BeforeAll {
+            $TestParams = @{
+                Group = "WebServers"
+            }
+
+            $Result = Remove-CCMGroup @TestParams -Confirm:$false
+        }
+
+        It "Calls Get-CCMGroup to get the ID for the group" {
+            Should -Invoke Get-CCMGroup -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Group -eq $TestParams.Group
+            }
+        }
+
+        It "Calls the API to remove the group" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Method -eq "DELETE" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/Delete" -and
+                $Uri.Query -eq "?id=$($TestParams.Group)ID" -and
+                $ContentType -eq "application/json"
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+    
+    Context "Removing multiple groups" {
+        BeforeAll {
+            $TestParams = @{
+                Group = "WebServers", "TestAppDeployment"
+            }
+
+            $Result = Remove-CCMGroup @TestParams -Confirm:$false
+        }
+
+        It "Calls Get-CCMGroup to get the ID for the group" {
+            foreach ($GroupName in $TestParams.Group) {
+                Should -Invoke Get-CCMGroup -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                    $Group -eq $GroupName
+                }
+            }
+        }
+
+        It "Calls the API to remove the group" {
+            foreach ($GroupName in $TestParams.Group) {
+                Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                    $Method -eq "DELETE" -and
+                    $Uri.AbsolutePath -eq "/api/services/app/Groups/Delete" -and
+                    $Uri.Query -eq "?id=$($GroupName)ID" -and
+                    $ContentType -eq "application/json"
+                }
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Remove-CCMGroupMember.Tests.ps1 b/src/Tests/Public/Remove-CCMGroupMember.Tests.ps1
new file mode 100644
index 0000000..edbb85a
--- /dev/null
+++ b/src/Tests/Public/Remove-CCMGroupMember.Tests.ps1
@@ -0,0 +1,99 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Remove-CCMGroupMember" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM -ParameterFilter {
+            $Method -eq "POST" -and
+            $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit"
+        } {
+            @{
+                success = $true
+            }
+        }
+        Mock Get-CCMGroupMember -ModuleName ChocoCCM {
+            @{
+                Id        = 1
+                Name      = "TestLab"
+                Computers = @(
+                    @{
+                        computerId = 1
+                        name       = "TestPC1"
+                    }
+                    @{
+                        computerId = 2
+                        name       = "TestPC2"
+                    }
+                )
+                Groups    = @(
+                    @{
+                        subGroupId = 3
+                        name       = "FirstLab"
+                    }
+                    @{
+                        subGroupId = 4
+                        name       = "SecondLab"
+                    }
+                )
+            }
+        }
+        Mock Get-CCMComputer -ModuleName ChocoCCM {
+            @{
+                Id   = 1
+                Name = "TestPC1"
+            }
+            @{
+                Id   = 2
+                Name = "TestPC2"
+            }
+            @{
+                Id   = 3
+                Name = "Test1"
+            }
+            @{
+                Id   = 4
+                Name = "Test2"
+            }
+        }
+        Mock Get-CCMGroup -ModuleName ChocoCCM
+    }
+
+    Context "Removing a computer from a group" {
+        BeforeAll {
+            $TestParams = @{
+                Group          = "TestLab"
+                ComputerMember = "TestPC1"
+            }
+
+            $Result = Remove-CCMGroupMember @TestParams
+        }
+
+        It "Calls the API to update the group object" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+                $Body.Computers.name -eq @("TestPC2") -and
+                "$($Body.Groups.name)" -eq "FirstLab SecondLab"
+            }
+        }
+
+        # TODO: This seems broken, but I'm not yet sure why. Returns [system.string[]] as if cast to string.
+        It "Returns an updated object representing the group" -Skip {
+            $Result | Should -Be [PSCustomObject]@{
+                Status            = $true
+                Group             = $TestParams.Group
+                AffectedComputers = $TestParams.ComputerMember
+                AffectedGroups    = $null
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Remove-CCMStaleDeployment.Tests.ps1 b/src/Tests/Public/Remove-CCMStaleDeployment.Tests.ps1
new file mode 100644
index 0000000..7887fee
--- /dev/null
+++ b/src/Tests/Public/Remove-CCMStaleDeployment.Tests.ps1
@@ -0,0 +1,47 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Remove-CCMStaleDeployment" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMDeployment -ModuleName ChocoCCM {
+            1..60 | ForEach-Object {
+                @{
+                    Deployment = $_
+                    CreationDate = (Get-Date).AddDays(-$_)
+                    Result = 0  # Is 0 really a bad state?
+                }
+            }
+        }
+        Mock Remove-CCMDeployment -ModuleName ChocoCCM
+    }
+
+    # This function is broken. It tries to use the -All parameter of Get-CCMDeployment, but that parameter doesn't exist.
+    Context "Removing Stale Deployments" -Skip {
+        BeforeAll {
+            $TestParams = @{
+                Age = "30"
+            }
+
+            $Result = Remove-CCMStaleDeployment @TestParams -Confirm:$false
+        }
+
+        It "Calls Get-CCMDeployment to find all existing deployments" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly
+        }
+
+        It "Calls Remove-CCMDeployment to remove deployments with age greater than 30 days" {
+            Should -Invoke Remove-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 30 -Exactly -ParameterFilter {
+                $Deployment -ge 30  # This test could be improved, but as the function is broken it is what it is.
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Set-CCMDeploymentStep.Tests.ps1 b/src/Tests/Public/Set-CCMDeploymentStep.Tests.ps1
new file mode 100644
index 0000000..9bc1446
--- /dev/null
+++ b/src/Tests/Public/Set-CCMDeploymentStep.Tests.ps1
@@ -0,0 +1,111 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Set-CCMDeploymentStep" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMDeployment -ModuleName ChocoCCM
+    }
+
+    # Skipping: This function is currently not fully implemented
+    Context "Setting a basic deployment step" -Skip {
+        BeforeAll {
+            $TestParams = @{
+                Deployment              = "Google Chrome Update"
+                Step                    = "Upgrade"
+                TargetGroup             = "LabPCs"
+                ExecutionTimeoutSeconds = 14400
+                ChocoCommand            = "Upgrade"
+                PackageName             = "googlechrome"
+            }
+
+            $Result = Set-CCMDeploymentStep @TestParams
+        }
+
+        It "Calls Get-CCMDeployment to get the deployment ID" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq $TestParams.Deployment
+            }
+        }
+
+        It "Calls Get-CCMDeployment to get the existing configuration" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Id -eq "$($TestParams.Deployment)ID"
+            }
+        }
+
+        It "Calls the API to update the deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Role/GetRoles" -and
+                $Uri.Query -eq "?permission=" -and
+                $ContentType -eq "application/json" -and
+                $Body.usernameOrEmailAddress -eq $TestParams.Credential.UserName -and
+                $Body.password -eq $TestParams.Credential.GetNetworkCredential().Password
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    # Skipping: This function is currently not fully implemented
+    Context "Setting a complex deployment step" -Skip {
+        BeforeAll {
+            $TestParams = @{
+                Deployment              = "OS Version"
+                Step                    = "Gather Info"
+                TargetGroup             = "US-East servers"
+                Script                  = {
+                    $data = Get-WMIObject win32_OperatingSystem
+                    [pscustomobject]@{
+                        Name    = $data.caption
+                        Version = $data.version
+                    }
+                }
+            }
+
+            $Result = Set-CCMDeploymentStep @TestParams
+        }
+
+        It "Calls Get-CCMDeployment to get the deployment ID" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq $TestParams.Deployment
+            }
+        }
+
+        It "Calls Get-CCMDeployment to get the existing configuration" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Id -eq "$($TestParams.Deployment)ID"
+            }
+        }
+
+        It "Calls the API to update the deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "GET" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Role/GetRoles" -and
+                $Uri.Query -eq "?permission=" -and
+                $ContentType -eq "application/json" -and
+                $Body.usernameOrEmailAddress -eq $TestParams.Credential.UserName -and
+                $Body.password -eq $TestParams.Credential.GetNetworkCredential().Password
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Set-CCMGroup.Tests.ps1 b/src/Tests/Public/Set-CCMGroup.Tests.ps1
new file mode 100644
index 0000000..50566f2
--- /dev/null
+++ b/src/Tests/Public/Set-CCMGroup.Tests.ps1
@@ -0,0 +1,134 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Set-CCMGroup" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMGroupMember -ModuleName ChocoCCM {
+            @{
+                Id          = 1
+                Name        = $Group
+                Description = "An existing description"
+                Computers   = @()
+                Groups      = @()
+            }
+        }
+    }
+
+    Context "Updating a description" {
+        BeforeAll {
+            $TestParams = @{
+                Group          = "Finance"
+                NewDescription = "Computers in the finance division"
+            }
+
+            $Result = Set-CCMGroup @TestParams
+        }
+
+        It "Gets the existing group information" {
+            Should -Invoke Get-CCMGroupMember -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Group -eq $TestParams.Group
+            }
+        }
+
+        It "Calls the API to update the group" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+
+                $Body.Id -eq 1 -and
+                $Body.Name -eq $TestParams.Group -and
+                $Body.Description -eq $TestParams.NewDescription
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Updating a name" {
+        BeforeAll {
+            $TestParams = @{
+                Group   = "IT"
+                NewName = "TheBestComputers"
+            }
+
+            $Result = Set-CCMGroup @TestParams
+        }
+
+        It "Gets the existing group information" {
+            Should -Invoke Get-CCMGroupMember -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Group -eq $TestParams.Group
+            }
+        }
+
+        It "Calls the API to update the group" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+
+                $Body.Id -eq 1 -and
+                $Body.Name -eq $TestParams.NewName -and
+                $Body.Description -eq "An existing description"  # Has not been changed
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Updating a name and description" {
+        # Set-CCMGroup -Group Test -NewName NewMachineImaged -Description 'Group for freshly imaged machines needing a baseline package pushed to them'
+        BeforeAll {
+            $TestParams = @{
+                Group          = "Test"
+                NewName        = "NewMachineImaged"
+                NewDescription = "Group for freshly imaged machines needing a baseline package pushed to them"
+            }
+
+            $Result = Set-CCMGroup @TestParams
+        }
+
+        It "Gets the existing group information" {
+            Should -Invoke Get-CCMGroupMember -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Group -eq $TestParams.Group
+            }
+        }
+
+        It "Calls the API to update the group" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Groups/CreateOrEdit" -and
+                $ContentType -eq "application/json" -and
+
+                $Body.Id -eq 1 -and
+                $Body.Name -eq $TestParams.NewName -and
+                $Body.Description -eq $TestParams.NewDescription
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Set-CCMNotificationStatus.Tests.ps1 b/src/Tests/Public/Set-CCMNotificationStatus.Tests.ps1
new file mode 100644
index 0000000..1e1da1a
--- /dev/null
+++ b/src/Tests/Public/Set-CCMNotificationStatus.Tests.ps1
@@ -0,0 +1,70 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Set-CCMNotificationStatus" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+    }
+
+    Context "Setting notification On" {
+        BeforeAll {
+            $TestParams = @{
+                Enable = $true
+            }
+
+            $Result = Set-CCMNotificationStatus @TestParams
+        }
+
+        It "Calls the API to set the notification status" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "PUT" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Notification/UpdateNotificationSettings" -and
+                $ContentType -eq "application/json" -and
+                $Body.receiveNotifications -eq $true -and
+                $Body.notifications.name -eq "App.NewUserRegistered" -and
+                $Body.notifications.isSubscribed -eq $true
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+
+    Context "Setting notification Off" {
+        BeforeAll {
+            $TestParams = @{
+                Disable = $true
+            }
+
+            $Result = Set-CCMNotificationStatus @TestParams
+        }
+
+        It "Calls the API to set the notification status" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "PUT" -and
+                $Uri.AbsolutePath -eq "/api/services/app/Notification/UpdateNotificationSettings" -and
+                $ContentType -eq "application/json" -and
+                $Body.receiveNotifications -eq $false -and
+                $Body.notifications.name -eq "App.NewUserRegistered" -and
+                $Body.notifications.isSubscribed -eq $true
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Start-CCMDeployment.Tests.ps1 b/src/Tests/Public/Start-CCMDeployment.Tests.ps1
new file mode 100644
index 0000000..6d324c6
--- /dev/null
+++ b/src/Tests/Public/Start-CCMDeployment.Tests.ps1
@@ -0,0 +1,51 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Start-CCMDeployment" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMDeployment -ModuleName ChocoCCM {
+            @{
+                Id   = "$($Name)ID"
+                Name = $Name
+            }
+        }
+    }
+
+    Context "Starting a deployment" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment = "Complex Deployment"
+            }
+
+            $Result = Start-CCMDeployment @TestParams
+        }
+
+        It "Gets the deployment ID from Get-CCMDeployment" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq $TestParams.Deployment
+            }
+        }
+
+        It "Calls the API to start the deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/Start" -and
+                $ContentType -eq "application/json" -and
+                $Body.id -eq "$($TestParams.Deployment)ID"
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/Public/Stop-CCMDeployment.Tests.ps1 b/src/Tests/Public/Stop-CCMDeployment.Tests.ps1
new file mode 100644
index 0000000..247c41d
--- /dev/null
+++ b/src/Tests/Public/Stop-CCMDeployment.Tests.ps1
@@ -0,0 +1,51 @@
+Import-Module $PSScriptRoot\..\..\ChocoCCM.psd1
+
+Describe "Stop-CCMDeployment" {
+    BeforeAll {
+        InModuleScope -ModuleName ChocoCCM {
+            $script:Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
+            $script:HostName = "localhost"
+            $script:Protocol = "http"
+        }
+        Mock Invoke-RestMethod -ModuleName ChocoCCM
+        Mock Get-CCMDeployment -ModuleName ChocoCCM {
+            @{
+                Id   = "$($Name)ID"
+                Name = $Name
+            }
+        }
+    }
+
+    Context "Stopping a deployment" {
+        BeforeAll {
+            $TestParams = @{
+                Deployment = "Upgrade VLC"
+            }
+
+            $Result = Stop-CCMDeployment @TestParams -Confirm:$false
+        }
+
+        It "Gets the Deployment ID from Get-CCMDeployment" {
+            Should -Invoke Get-CCMDeployment -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                $Name -eq $TestParams.Deployment
+            }
+        }
+
+        It "Calls the API to stop the deployment" {
+            Should -Invoke Invoke-RestMethod -ModuleName ChocoCCM -Scope Context -Times 1 -Exactly -ParameterFilter {
+                if ($Body -is [string]) {
+                    $Body = $Body | ConvertFrom-Json
+                }
+
+                $Method -eq "POST" -and
+                $Uri.AbsolutePath -eq "/api/services/app/DeploymentPlans/Cancel" -and
+                $ContentType -eq "application/json" -and
+                $Body.id -eq "$($TestParams.Deployment)ID"
+            }
+        }
+
+        It "Returns Nothing" {
+            $Result | Should -BeNullOrEmpty
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tests/chococcm.tests.ps1 b/src/Tests/chococcm.tests.ps1
index 05c757e..24367ce 100644
--- a/src/Tests/chococcm.tests.ps1
+++ b/src/Tests/chococcm.tests.ps1
@@ -16,5 +16,3 @@ Describe "Module Import Checks" {
         { Get-Command -Module ChocoCCM } | Should -Not -Throw
     }
 }
-
-#TODO: Lots of mocks for actual function tests
diff --git a/test.ps1 b/test.ps1
new file mode 100644
index 0000000..70e43b0
--- /dev/null
+++ b/test.ps1
@@ -0,0 +1,36 @@
+param (
+    [String] $Path = ".",
+    [String] $Output = "Detailed",
+    [Switch] $CodeCoverage
+)
+
+Import-Module Pester -MinimumVersion 5.2.0
+
+$Configuration = [PesterConfiguration]::Default
+
+$Configuration.Run.Path = $Path
+
+$Configuration.Output.Verbosity = $Output
+
+$Configuration.CodeCoverage.Enabled = [bool] $CodeCoverage
+# CoverageGutters is new option in Pester 5.2
+$Configuration.CodeCoverage.UseBreakpoints = $false
+$Configuration.CodeCoverage.OutputFormat = "CoverageGutters"
+$Configuration.CodeCoverage.Path = "$PSScriptRoot/src"
+$Configuration.CodeCoverage.OutputPath = "$PSScriptRoot/coverage.xml"
+$Configuration.CodeCoverage.CoveragePercentTarget = 90
+
+$Configuration.Debug.WriteDebugMessages = $true
+$Configuration.Debug.WriteDebugMessagesFrom = "CodeCoverage"
+
+
+# for convenience just run the passed file when we invoke this via launchConfig.json when
+# the file is a non-test file
+$isDirectory = (Get-Item $Path).PSIsContainer
+$isTestFile = $Path.EndsWith($Configuration.Run.TestExtension.Value)
+if (-not $isDirectory -and -not $isTestFile) {
+    & $Path
+    return
+}
+
+Invoke-Pester -Configuration $Configuration
\ No newline at end of file