Cannot Associate Test Case in Visual Studio - c#

I have a standard MSTest unit test in a unit test C# project file. The project is running .NET Framework 4.7.2, and has version 1.3.2 of the MSTest adapter and framework installed. I am running Visual Studio 2017 Enterprise 15.7.6, and have a VSTS workspace with some random manually-created test cases in it.
When I right-click on my unit test in the Test Explorer, and select "Associate to Test Case", I am able to enter the test case ID, add the association, and click "Save". Upon save, I get an error message, below.
I have tried to save the association using different versions of MSTest, and different .NET Framework versions for the project file, neither of which solved the issue. I also tried running Visual Studio as an administrator, which did not work. Has anyone else had this issue, or know of any workarounds?

I test it in my side using two VS2017 versions, they all works well.
For example, I add a simple test case manually in one test plan in VSTS, and then I create a simple unit test project with .net 4.7.2 in my side using VS2017 15.7.6, I could a associate to Test Case in my side.
If possible, you could test it in your side with the following steps:
(1) Test it with other VS machines(The same VS version but not in the same machine if you have).
(2) Clean the VSTS cache. Clean and rebuild your test project in solution explorer window, test it again.
(3) Tools->Options->Work Items, select "Visual Studio(Compatibility mode)" there.
(4) If still no help, add a new test simple unit test project in your VS, uremove the nuget packages: MSTest.TestAdapter and MSTest.TestFramework, and then add a local reference to Microsoft.VisualStudio.QualityTools.UnitTestFramework, view the result again.
Update:
I update my VS2017 to the 15.8.1 version, I got the same issue, that option was disable in default. It would be a real feedback.
https://developercommunity.visualstudio.com/content/problem/309413/cannot-associate-test-case-in-visual-studio.html?childToView=311392#comment-311392
Other members who get the same issue could vote it.

A work around I put together and now use exclusively instead of manual association is to supply the test case id in the test method name and automatically update the case in TFS via the rest API by adding the following PowerShell script to run on a successful build in TFS.
A GUID for each test is generated using the full namespace for the test method and needs to be added to "/fields/Microsoft.VSTS.TCM.AutomatedTestId"
This would need adjusted to your own TFS authentication methods and possibly TFS version (I'm using 2017.2) along with the type of tests you need to read in. This is supporting Coded UI and xUnit. The LoadFrom at the top can be removed if you are not using Coded UI at all.
param (
[string]$Dll = $(throw "-path to test Dll is required.")
)
Write-Warning "$Dll will be locked until this powershell session closes"
#Load for CodedUi Support
[Reflection.Assembly]::LoadFrom(("C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.TestTools.UITesting.dll"))
[Reflection.Assembly]::LoadFrom(("C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll"))
try {
$tests = ([Reflection.Assembly]::LoadFrom(($Dll)).GetTypes().GetMethods() | Where-Object { $_.GetCustomAttributes($false) | Where-Object {$_.TypeId.Name -icontains 'TestMethodAttribute' -or $_.TypeId.Name -icontains 'FactAttribute' -or $_.TypeId.Name -icontains 'SkippableFactAttribute' -or $_.TypeId.Name -icontains 'TheoryAttribute'}} | ForEach-Object { #{ Class = $_.DeclaringType.Name; Name = $_.Name; FullName = $_.DeclaringType.FullName + "." + $_.Name; }})
}
catch {
Write-Error "Could not load or read $dll" -ErrorAction Stop
}
foreach ($test in $tests)
{
$sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider;
$nameHash = $sha1.ComputeHash([System.Text.Encoding]::Unicode.GetBytes($test.FullName));
[byte[]]$toGuid = [System.Byte[]]::CreateInstance([System.Byte],16);
[System.Array]::Copy($nameHash, $toGuid, 16);
$guid = [guid]::new($toGuid);
$id = ([Regex]::Match($test.Name, "(\d+)(?!.*\d)").Value)
try {
if ($psversiontable.PSVersion.Major -lt 6) {
$currentGUID = (Invoke-RestMethod "http://{instance}[/{team-project}]/_apis/wit/workitems/$($id)?api-version=3.0-preview" -Method Get -UseBasicParsing -UseDefaultCredentials).Fields.'Microsoft.VSTS.TCM.AutomatedTestId'
}
else {
$currentGUID = (Invoke-RestMethod "http://{instance}[/{team-project}]/_apis/wit/workitems/$($id)?api-version=3.0-preview" -Method Get -UseBasicParsing -UseDefaultCredentials -AllowUnencryptedAuthentication).Fields.'Microsoft.VSTS.TCM.AutomatedTestId'
}
}
catch {
$currentGUID = $null;
}
if($currentGUID -ne $guid)
{
Write-Host "Updating $id."
[array]$hash = #{
op = "add";
path = "/fields/Microsoft.VSTS.TCM.AutomatedTestName";
from = $null;
value = $test.FullName;
},#{
op = "add";
path = "/fields/Microsoft.VSTS.TCM.AutomatedTestStorage";
from = $null;
value = (Split-Path $DLL -leaf);
},#{
op = "add";
path = "/fields/Microsoft.VSTS.TCM.AutomatedTestId";
from = $null;
value = $guid;
},#{
op = "add";
path = "/fields/Microsoft.VSTS.TCM.AutomationStatus";
from = $null;
value = "Automated";
},#{
op = "add";
path = "/fields/System.Reason";
from = $null;
value = "Completed";
},#{
op = "add";
path = "/fields/System.State";
from = $null;
value = "Ready";
}
$patch = Convertto-json $hash -Compress
write-host $test.Name
write-host "http://{instance}[/{team-project}]/_apis/wit/workitems/$($id)?api-version=3.0-preview"
if ($psversiontable.PSVersion.Major -lt 6) {
$result = Invoke-RestMethod "http://{instance}[/{team-project}]/_apis/wit/workitems/$($id)?api-version=3.0-preview" -Method Patch -UseBasicParsing -UseDefaultCredentials -Body $patch -ContentType "application/json-patch+json"
}
else {
$result = Invoke-RestMethod "http://{instance}[/{team-project}]/_apis/wit/workitems/$($id)?api-version=3.0-preview" -Method Patch -UseBasicParsing -UseDefaultCredentials -Body $patch -ContentType "application/json-patch+json" -AllowUnencryptedAuthentication
}
}
else {
Write-Host "No changes to $id."
}
}

Related

How to get Build Id from tfs during the build in C#

To get a log link i need the id of current build, I tried to use this in my C# code, but it didn't return Build Id:
var envVars;
envVars = Environment.GetEnvironmentVariables();
To get the Build.Id during the build with C# you can sue this line:
string buildId = Environment.GetEnvironmentVariable("Build_BuildId",Environment.VariableTarget.Process);
You can get the build Id from this variable
$(Build.BuildId)
Pass it as parameter(exactly as it written here) to the tool(console app?) that you are building.
You can check other variables from this link
https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml
The solution is to put this var in txt file via PowerShell script, and than get it by C#
PS:
if(!(Test-Path -Path C:\BuildVariables)){
New-Item -ItemType directory -Path C:\BuildVariables
}
Out-File -FilePath C:\BuildVariables\buildId.txt -Force -InputObject $(Build.Buildid)
C#:
public static string ShowEnvironmentVariables()
{
string var = File.ReadAllText("C:\\BuildVariables\\buildId.txt");
return var;
}

Using powershell with .NET returning null

I am using .NET with powershell trying to retrieve result of Get-Acl command of specific AD object. Unfortunately when I run the code from C# code I get 0 result. Also the ThrowIfError is not throwing any error.
Command test01 = new Command("import-module");
test01.Parameters.Add("name", "activedirectory");
session.Commands.AddCommand(test01);
Command test0 = new Command("Set-Location");
test0.Parameters.Add("Path", "AD:");
session.Commands.AddCommand(test0);
Command test1 = new Command("Get-Acl");
test1.Parameters.Add("Path", identity);
session.Commands.AddCommand(test1);
session.AddCommand("select-object");
session.AddParameter("Property", "Access");
var tempResults1 = session.Invoke();
ThrowIfError();
private void ThrowIfError()
{
var errors = session.Streams.Error;
if (errors.Count > 0)
{
var ex = errors[0].Exception;
session.Streams.ClearStreams();
// Never close session to dispose already running scripts.
throw ex;
}
}
This code running on server in powershell is working correctly:
PS AD:\> Import-Module -Name activedirectory
PS AD:\> set-location ad:
PS AD:\> get-acl -path <distinguishedNameOfADObject>
Question
How to get the same result like I get from Powershell? I should get atleast something not a zero result.
Little background:
I am trying to get Send-As rights not using Get-ADPermission cmdlet because its taking too long time when I need to search for rights within thousands of mailboxes. Using this article link I am trying another approach to get the rights. I have already the slower version working using C# code:
Command command = new Command("Get-ADPermission");
command.Parameters.Add("Identity", identity);
session.Commands.AddCommand(command);
session.AddCommand("where-object");
ScriptBlock filter = ScriptBlock.Create("$_.ExtendedRights -eq 'send-as'");
session.AddParameter("FilterScript", filter);
session.AddCommand("select-object");
session.AddParameter("Property", "User");
tempResults = session.Invoke();
The better way is to define a powershell-script instead of multiple commands to get the values you need. Example with your powershell-code:
using System.Collections.ObjectModel;
using System.DirectoryServices;
using System.Management.Automation;
namespace GetAclPowershellTest
{
class Program
{
static void Main(string[] args)
{
/****Create Powershell-Environment****/
PowerShell PSI = PowerShell.Create();
/****Insert PowershellScript****/
string Content = "param($object); Import-Module ActiveDirectory; Set-Location AD:; Get-ACL -Path $object"; //Add Scrip
PSI.AddScript(Content);
PSI.AddParameter("object", "<distinguishedNameOfADObject>");
/****Run your Script with PSI.Invoke()***/
Collection<PSObject> PSIResults = PSI.Invoke();
/****All Errors****/
Collection<ErrorRecord> Errors = PSI.Streams.Error.ReadAll();
/****needed, because garbagecollector ignores PSI otherwise****/
PSI.Dispose();
/**** Your ACL-Object ****/
ActiveDirectorySecurity MyACL = (ActiveDirectorySecurity)PSIResults[0].BaseObject;
/*insert your code here*/
}
}
}
This example works for me.
You have to set a reference to the Powershell-Assembly (Usually you can find it at "C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll")
Benefit of this solution is, you could read a .ps1-File you got from someone, fill the parameters with the objects you have and the script runs like in a standard powershell-session. The only requirement to set parameters is the param-part in the Script.
More Infos about param: https://technet.microsoft.com/en-us/library/jj554301.aspx
Hope, this helps...
Greetings, Ronny
Update:
string Content = "param($object); Import-Module ActiveDirectory; Set-Location AD:; (Get-ACL -Path $object).Access | Where-Object{($_.ActiveDirectoryRights -eq 'ExtendedRight') -and ($_.objectType -eq 'ab721a54-1e2f-11d0-9819-00aa0040529b')}";
And the loop at the end looks like this now:
foreach (PSObject o in PSIResults)
{
ActiveDirectoryAccessRule AccessRule = (ActiveDirectoryAccessRule)o.BaseObject;
/**do something with the AccessRule here**/
}

NUnit Test on Jenkins fail (nunit xml result file is empty )

I recently started to build my C# Projects on a Jenkins build server.
But recently i had the problem that the reported NUnit xml is empty (the file is created but has no content.)
Console output is as follows
Process leaked file descriptors. See
http://wiki.jenkins-ci.org/display/JENKINS/Spawning+processes+from+build
for more information [WARNINGS] Parsing warnings in console log with
parser MSBuild [WARNINGS] Computing warning deltas based on reference
build #288 Recording NUnit tests results ERROR: Step ‘Publish NUnit
test result report’ aborted due to exception:
hudson.util.IOException2: Could not transform the NUnit report. Please
report this issue to the plugin author at
hudson.plugins.nunit.NUnitArchiver.invoke(NUnitArchiver.java:65) at
hudson.plugins.nunit.NUnitArchiver.invoke(NUnitArchiver.java:26) at
hudson.FilePath.act(FilePath.java:990) at
hudson.FilePath.act(FilePath.java:968) at
hudson.plugins.nunit.NUnitPublisher.perform(NUnitPublisher.java:145)
at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
at
hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:782)
at
hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:723)
at hudson.model.Build$BuildExecution.post2(Build.java:185) at
hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:668
i know that the problem are probably the leaked file descriptors, but i am not really sure how to fix that.
the NUnit tests are executed with a powershell script, that grabs all necessary dlls
powershell script:
param(
[string] $sourceDirectory = "./trunk/TestProjects/"
, $fileFilters = #("*UnitTest*.dll")
, [string]$filterText = "*\bin*"
)
#script that executes all unit tests available.
Write-Host "Source: $sourceDirectory"
Write-Host "File Filters: $fileFilters"
Write-Host "Filter Text: $filterText"
$cFiles = ""
$nUnitExecutable = "C:\Program Files (x86)\NUnit.org\nunit-console\nunit3-console.exe"
# look through all subdirectories of the source folder and get any unit test assemblies. To avoid duplicates, only use the assemblies in the bin folder
[array]$files = get-childitem $sourceDirectory -include $fileFilters -recurse | select -expand FullName | where {$_ -like $filterText}
foreach ($file in $files)
{
$cFiles = $cFiles + '"' + $file + '"' + " "
}
# set all arguments and execute the unit console
$argumentList = #("$cFiles", "--result=nunit-result.xml;format=nunit2","--framework=net-4.5","--process=Single")
$unitTestProcess = start-process -filepath $nUnitExecutable -argumentlist $argumentList -nonewwindow
echo "$nUnitExecutable $argumentList"
$exitCode = $unitTestProcess.ExitCode
exit $exitCode
this problem only happens if the script is executed via jenkins
#######################UPDATE
after some investigation i found out that his only happens when i add 1 testcase in which wpf controls are created by invoking them on the UI thread.
[Test Apartment(ApartmentState.STA) RunInApplicationDomain]
public void CheckPluginModel()
{
var app = Application.Current ?? new Application { ShutdownMode = ShutdownMode.OnExplicitShutdown };
PluginModel model = new PluginModel();
var task= model.LoadPluginsFromPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
RunApplication(() => task.IsCompleted);
Assert.That(model.AvailablePluginControls.Count, Is.EqualTo(1));
Assert.That(model.Workflows.Count, Is.EqualTo(1));
Console.WriteLine("Plugin model check finished");
}
RunApplication:
/// <summary>
/// Runs the application. as long as abortCriteria returns false
/// </summary>
/// <param name="abortCriteria">The abort criteria.</param>
private void RunApplication(Func<bool> abortCriteria, int duetime = 100, int period=100)
{
Console.WriteLine("Application started");
System.Threading.Timer timer = null;
timer = new Timer((obj) =>
{
if (abortCriteria.Invoke())
{
Application.Current.Dispatcher.Invoke(() => Application.Current.Shutdown());
timer.Dispose();
}
}, null, duetime, period);
Application.Current.Run();
Console.WriteLine("Application stopped");
}
All GUI elements are created
await Application.Current.Dispatcher.BeginInvoke(new Action(() => AvailablePluginControls.Add((APControl)Activator.CreateInstance(item))),null);
Nunit Plugin in Jenkins is not support Nunit 3 xml format. I also the similar problem on Jenkins. I used to convert Nunit 3 result format to Nunit 2 format.
"C:\NUnit 3.5.0\nunit3-console.exe" /result:\MyApplication.xml;format=nunit2 "D:\Jenkins\workspace\MyApplication.Tests.dll"
The problem was as followed:
The unit tests are executed via the powershell script.
The powershell start process does not wait untill the process has finished. This causes the problem that a child process is not finished.
in order for start-process to wait until the process has finished, the flag -Wait has to be added.

Accessing Sharepoint document library list using Windows PowerShell script

Task: I need to loop thru all files on Sharepoint site and download them to local folder.
Script:
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$s = Get-SPSite “https://abc.abctools.consumer.abc.net/sites/rtc/report/SitePages/Forms/AllPages.aspx”
$files = $s.RootWeb.GetFolder("Shared Documents").Files
foreach ($file in $files) {
Write-host $file.Name
$b = $file.OpenBinary()
$fs = New-Object System.IO.FileStream(("C:\SP Document Library files\"+$file.Name), [System.IO.FileMode]::Create)
$bw = New-Object System.IO.BinaryWriter($fs)
$bw.Write($b)
$bw.Close()
}
Errors: I get when i try to run/execute above script.
1. "You cannot call a method on a null-valued expression."
New-Object: Exception calling ".ctor" with "2" agrument(s): "Could not find a part of the path 'C:\SP Document Library files\'
New-Object: Constructor not found. Cannot find an appropriate constructor for the type system.IO.BinaryWrite.
The term 'Get-SPSite' is not recognized as a cmdlet, function, operable program or script file. verify the term and try again.
Response on Error #2: I have created the folder & named "SP Document Library files" so that path is correct C:\SP Document Library files not sure why i see that msg.
Library files (.csv,.xls) exists in a folder.
Folder name : 2014-01-31.
1. What to do to in order resolve above error message(s).
2. I'm not sure if i need to use whole sharepoint url or part of it.Educate me on that.
Thanks!!
Try by giving ReadWrite FileAccess.
And you can get the root web directly if you know the Url instead of using SPSite.
Here's my script I use and has always worked
$siteUrl = '“https://abc.abctools.consumer.abc.net/sites/rtc”'
$listUrl = '“https://abc.abctools.consumer.abc.net/sites/rtc/Shared Documents”'
$folderPath = 'C:\\....'
$web = Get-SPWeb -Identity $siteUrl
$list = $web.GetList($listUrl)
$items = $list.Items
ForEach ($item in $items)
{
$binary = $item.File.OpenBinary();
$folderPathToSave = $folderPath + "\\" + $item.Name;
if ($binary -ne $null)
{
$stream = New-Object System.IO.FileStream($folderPathToSave,[System.IO.FileMode]::Create,[System.IO.FileAccess]::ReadWrite);
$writer = New-Object System.IO.BinaryWriter($stream);
$writer.Write($binary);
$writer.Close();
}
}
$web.Dispose()
The original post:
http://naimmurati.wordpress.com/2012/06/07/backup-documents-from-document-library-with-powershell-script/

specify build action of content - Nuget

What is the simplest way to tell Nuget package to add all css files as an embedded resource (ie build action is embedded resource).
I am trying to do it through install.ps1 in the tools folder but still cant get anywhere
Note: I am creating the package from the directory structure(tools\content\lib)
This is my install.ps1 which does not work.
param($installPath, $toolsPath, $package, $project)
$MsbNS = #{msb = 'http://schemas.microsoft.com/developer/msbuild/2003'}
function EmbeddContent($ProjectLink, [string]$XPath)
{
$nodes = #(Select-Xml $XPath $ProjectLink -Namespace $MsbNS | Foreach {$_.Node})
foreach ($node in $nodes)
{
if($node.Include.StartsWith("Content\css"))
{
$cet = $node.ownerdocument.CreateElement("EmbeddedResource")
$cet.setAttribute("Include", $node.Include)
$parent = $node.ParentNode
[void]$parent.RemoveChild($node)
[void]$parent.Appendchild($cet)
}
}
}
$project.Save()
$fileLocation = $project.FileName
$dte.ExecuteCommand("Project.UnloadProject");
$proj = [xml](gc $fileLocation)
Embeddcontent $fileLocation '//msb:Project/msb:ItemGroup/msb:Content'
$proj.Save($fileLocation)
Help Please ..
You can use DTE instead of messing with xml to change the BuildAction. From http://nuget.codeplex.com/discussions/227696:
$item = $project.ProjectItems | where-object {$_.Name -eq "ReleaseNotes.txt"}
$item.Properties.Item("BuildAction").Value = [int]3
This link shows the enumeration values:
http://msdn.microsoft.com/en-us/library/aa983962(VS.71).aspx

Categories