Directory disappears after test concludes - c#

I'm trying to put the output of a UnitTest in an intellgent location so I can:
Run the test multiple times and either overwrite or create new results
Find the results / trace / log files I create
Avoid hard coding the path
The advice seems to be to use TestContext (https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.testtools.unittesting.testcontext?view=mstest-net-1.2.0). My unit test correctly populates this object; I can see that as I'm debugging.
I've tried writing to several files and come up with frustrating results.
Write to a file in the Test Directory
string fileOutput = Path.Combine(m_testContext.TestDir, "readmeBasic.txt");
using (System.IO.StreamWriter file = new System.IO.StreamWriter(fileOutput))
{
file.WriteLine("Basic Data");
...
}
Write a trace message
m_testContext.WriteLine("Test Directory " + m_testContext.TestDir);
When I execute my code, I can see the readmeBasic.txt appear. Using Notepad++ during execution of the unit test, the file appears empty even after several WriteLine statements. After successful, error free execution of my unit test, the directory with the file gets removed (by Visual Studio ???).
Is there a configuration I'm missing?
Where is there documentation that explains why this directory gets removed?
What is the point of providing this information in m_testcontext if it is transient and will get removed?
Visual Studio 2019 16.3.9

Yes, the deployment folder will be deleted by default when the test runs
successfully.
If you want to save the folder, you could create a runsettings file, then set “DeleteDeploymentDirectoryAfterTestRunIsComplete” to false, the configuration will retain the deployment folder after a test run.
Please follow this doc to create a runsetting file, then type the below code:
In addition, the ”Testcontext” is used to get some information of running test, such as test name, test outcome and etc. The testcontext.writeline will write into test output, which will input to trx file, so you may need to use file.writeline() to record trace message.
BTW, you could refer this sample about logging current TestMethod with result:
[TestCleanup]
public void LogResult()
{
var testOutcome = TestContext.CurrentTestOutcome;
string testName = TestContext.TestName;
string testdir = Path.Combine(TestContext.TestDir,"log.txt");
string str = testName + ": " + testOutcome.ToString() + "\n";
using (System.IO.StreamWriter file = new System.IO.StreamWriter(testdir))
{
file.WriteLine(str);
file.WriteLine("Basic Data");
}
}
public TestContext TestContext
{
get { return testContextInstance; }
set { testContextInstance = value; }
}
private TestContext testContextInstance;

Related

Why is my application trying to read objects in the wrong folder?

I'm using visual studio to do my first full release of an application, which is a simple WPF GUI to configure a locally saved JSON object, and a console application to run in the background, using data from that object to monitor a website. I published each project to a test folder (we'll say Publish/), where each application manifest now resides, along with an 'Application Files' folder containing another sub-folder for each project.
I got the applications to run just fine - the problem is the configuration file saves to one folder a few more levels into C:\Users\username\AppData\Local\Apps\2.0\ and the console application is attempting to read from a completely separate folder. Both projects write and read using GetCurrentDirectory() for the file path. Is there a way I'm missing to remedy this?
Code for retrieving JSON object
try
{
//Confirms file exists
if (File.Exists(Directory.GetCurrentDirectory().ToString() + filePath))
{
//Initialize json variable to a string, then deserialize it into an instance of RCDetails
var json = File.ReadAllText(Directory.GetCurrentDirectory().ToString() + filePath);
RCDetails parsedDetails = JsonConvert.DeserializeObject<RCDetails>(json);
//Return deserialized JSON
return parsedDetails;
}
else return null;
And code for writing json object
public void WriteToFile(RCDetails rcd)
{
//Serialize input instance of RCDetails class
string JSONresult = JsonConvert.SerializeObject(rcd, Formatting.Indented);
//Remove old JSON object
if (File.Exists(Directory.GetCurrentDirectory().ToString() + jsonFilePath))
File.Delete(Directory.GetCurrentDirectory().ToString() + jsonFilePath);
//Create new JSON object with updated details
File.WriteAllText(Directory.GetCurrentDirectory().ToString() + jsonFilePath, JSONresult);
}
Exact steps for publishing project:
With console app selected, click Build > Publish (console app name)
Browse to C:\Users\username\Downloads\Publish\
For installation, choose "From a CD-ROM or DVD-ROM"
Select "the application will not check for updates
Select finish, and repeat all steps with same file path for config WPF
Solution I wound up finding (feel free to let me know if this is a bad plan). I just plopped this into both apps.
string s = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\IntendedFolder";
if (!Directory.Exists(s))
Directory.CreateDirectory(s);
Directory.SetCurrentDirectory(s);

Stopping a test in C# visual studio if no data exist with smoke test

I have a pack of smoke test that run and randomly pull data from a table and search by that data in another method and assert after. The test will fail if no data exist. I have a reusable method called RandomVinSelect(). I want to stop the test if there is no data. I have searched for test result warnings that test could not be ran instead of failing the test. At this point I am stumped. This is the code I have I do not want to run the lines after UI.RandomVINSelect if no data found. I am thinking there may not be a way for this using Xunit and it would just be pass or fail...
public static string RandomVinSelect(this Browser ui, string table,
string selector)
{
//I want to stop test here if no data exist or create a dataexist
//method that stops a test.
int rows = ui.GetMultiple(table).Count;
Random num = new Random();
string randomnum = Convert.ToString(num.Next(1, rows));
string newselector = selector.Replace("1", randomnum);
string vin = ui.Get(newselector).Text;
return vin;
}
Perhaps just put smoke tests in a separate test package or collection and include a test that just checks to see if it can get data, then when you run this group of tests if that first test fails you know it is just due to no data being available.
Not ideal but might be good enough?
I installed the new nuget package(xunit.SkippableFact) added [SkippableFact] to my smoke test. Then I created a method that can be called to check and see if data is available and runs a Skip.If(condition,"my message") within that method and closes the test early if no data is present. Then in the Test Explorer show a warning symbol.
public static void IsDataAvaiable(this Browser ui)
{
bool data = true;
string pagecount = ui.GetPageCount();
if (pagecount == "0") data = false;
Skip.If(data == false, "The test could not run because no data available for validation.");
}

Cannot get ValidStates of WindowsInstaller features

I've encountered a problem when I try to retrieve the valid states of all features within an MSI package using the Microsoft.Deployment.WindowsInstaller.Installer class.
I want to copy the ValidStates property of each FeatureInfo within a Session. However when doing so I get a "Handle is in an invalid state." exception.
If I print each of these values out using Console.WriteLine() or step through the code in Visual Studio there is no exception.
I am at a loss as to what is preventing me from doing this.
Thanks in advance!
My Code:
var featureDictionary = new Dictionary<string, string[]>();
if (string.IsNullOrWhiteSpace(mPath))
return featureDictionary;
try
{
Installer.SetInternalUI(InstallUIOptions.Silent);
using (var session = Installer.OpenPackage(mPath, true))
{
foreach (var feature in session.Features)
{
try
{
var states = feature.ValidStates.Select((state) => state.ToString());
featureDictionary.Add(feature.Name, states.ToArray());
}
catch (InstallerException ex)
{
Debug.WriteLine(ex.Message);
}
}
}
}
catch (InstallerException) { }
return featureDictionary;
The basic problem appears to be that you are opening the MSI as a file. Since you haven't posted its declaration, or how it is set, I'm assuming that mpath means it's a path to the file. Your OpenPackage method parameters seem to indicate this too. You're getting that error because you are trying to open the MSI file as a file during the actual install, and failing.
The way to get hold of the database for the running install is to use Session.Database.
You can't open the running MSI as a file during the install perhaps for the same reason you can't run an MSI file that you have open with Orca, a simple file sharing violation. When you step through with Visual Studio you're simply accessing the static file and getting default values and the file isn't being used for an install. The other issue is that there can only be one Session object per process (as the OpenPackage docs say) and you are attempting to get a second one while there is already a Session object associated with the handle of the install.
As a custom action it needs to be sequenced after CostFinalize.
Windows Installer conditional expressions such as !feature-state will tell you what state the feature is in, because it's usually better to avoid code where Windows Installer will just give you the answer.

How to get Directory while running unit test

Hi when running my unit test I'm wanting to get the directory my project is running in to retrieve a file.
Say I have a Test project named MyProject. Test I run:
AppDomain.CurrentDomain.SetupInformation.ApplicationBase
and I receive "C:\\Source\\MyProject.Test\\bin\\Debug".
This is close to what I'm after. I don't want the bin\\Debug part.
Anyone know how instead I could get "C:\\Source\\MyProject.Test\\"?
I would do it differently.
I suggest making that file part of the solution/project. Then right-click -> Properties -> Copy To Output = Copy Always.
That file will then be copied to whatever your output directory is (e.g. C:\Source\MyProject.Test\bin\Debug).
Edit: Copy To Output = Copy if Newer is the better option
Usually you retrieve your solution directory (or project directory, depending on your solution structure) like this:
string solution_dir = Path.GetDirectoryName( Path.GetDirectoryName(
TestContext.CurrentContext.TestDirectory ) );
This will give you the parent directory of the "TestResults" folder created by testing projects.
Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;
This will give you the directory you need....
as
AppDomain.CurrentDomain.SetupInformation.ApplicationBase
gives nothing but
Directory.GetCurrentDirectory().
Have alook at this link
http://msdn.microsoft.com/en-us/library/system.appdomain.currentdomain.aspx
Further to #abhilash's comment.
This works in my EXE's, DLL's and when tested from a different UnitTest project in both Debug or Release modes:
var dirName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location.Replace("bin\\Debug", string.Empty));
/// <summary>
/// Testing various directory sources in a Unit Test project
/// </summary>
/// <remarks>
/// I want to mimic the web app's App_Data folder in a Unit Test project:
/// A) Using Copy to Output Directory on each data file
/// D) Without having to set Copy to Output Directory on each data file
/// </remarks>
[TestMethod]
public void UT_PathsExist()
{
// Gets bin\Release or bin\Debug depending on mode
string baseA = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
Console.WriteLine(string.Format("Dir A:{0}", baseA));
Assert.IsTrue(System.IO.Directory.Exists(baseA));
// Gets bin\Release or bin\Debug depending on mode
string baseB = AppDomain.CurrentDomain.BaseDirectory;
Console.WriteLine(string.Format("Dir B:{0}", baseB));
Assert.IsTrue(System.IO.Directory.Exists(baseB));
// Returns empty string (or exception if you use .ToString()
string baseC = (string)AppDomain.CurrentDomain.GetData("DataDirectory");
Console.WriteLine(string.Format("Dir C:{0}", baseC));
Assert.IsFalse(System.IO.Directory.Exists(baseC));
// Move up two levels
string baseD = System.IO.Directory.GetParent(baseA).Parent.FullName;
Console.WriteLine(string.Format("Dir D:{0}", baseD));
Assert.IsTrue(System.IO.Directory.Exists(baseD));
// You need to set the Copy to Output Directory on each data file
var appPathA = System.IO.Path.Combine(baseA, "App_Data");
Console.WriteLine(string.Format("Dir A/App_Data:{0}", appPathA));
// C:/solution/UnitTestProject/bin/Debug/App_Data
Assert.IsTrue(System.IO.Directory.Exists(appPathA));
// You can work with data files in the project directory's App_Data folder (or any other test data folder)
var appPathD = System.IO.Path.Combine(baseD, "App_Data");
Console.WriteLine(string.Format("Dir D/App_Data:{0}", appPathD));
// C:/solution/UnitTestProject/App_Data
Assert.IsTrue(System.IO.Directory.Exists(appPathD));
}
I normally do it like that, and then I just add "..\..\" to the path to get up to the directory I want.
So what you could do is this:
var path = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + #"..\..\";
For NUnit this is what I do:
// Get the executing directory of the tests
string dir = NUnit.Framework.TestContext.CurrentContext.TestDirectory;
// Infer the project directory from there...2 levels up (depending on project type - for asp.net omit the latter Parent for a single level up)
dir = System.IO.Directory.GetParent(dir).Parent.FullName;
If required you can from there navigate back down to other directories if required:
dir = Path.Combine(dir, "MySubDir");
According to https://github.com/nunit/nunit/issues/742#issuecomment-121964506
For NUnit3 , System.Environment.CurrentDirector is never changed, so it shall be the path of solution.
Eg:
string szProjectPath = System.Environment.CurrentDirectory + #"\where\your\project\is";
I prefer fixed location rather than GetParent().
One drawback of GetParent is when build is changed from AnyCPU to x86, default path would be changed from bin\Debug to bin\x86\Debug.
Need to get another parent, and it's pain in the neck.
Also, you may still access to you test assemblies at TestContext.CurrentContext.TestDirectory and get output from TestContext.CurrentContext.WorkDirectory
Edit:
Note: There are many changes in NUnit3. I will suggest reading through the documentation about "Breaking changes"
The best solution I found was to put the file as an embedded resource on the test project and get it from my unit test. With this solution I don´t need to care about file paths.
I'm not sure if this helps, but this looks to be briefly touched on in the following question.
Visual Studio Solution Path environment variable
In general you may use this, regardless if running a test or console app or web app:
// returns the absolute path of assembly, file://C:/.../MyAssembly.dll
var codeBase = Assembly.GetExecutingAssembly().CodeBase;
// returns the absolute path of assembly, i.e: C:\...\MyAssembly.dll
var location = Assembly.GetExecutingAssembly().Location;
If you are running NUnit, then:
// return the absolute path of directory, i.e. C:\...\
var testDirectory = TestContext.CurrentContext.TestDirectory;
My approach relies on getting the location of the unit testing assembly and then traversing upwards. In the following snippet the variable folderProjectLevel will give you the path to the Unit test project.
string pathAssembly = System.Reflection.Assembly.GetExecutingAssembly().Location;
string folderAssembly = System.IO.Path.GetDirectoryName(pathAssembly);
if (folderAssembly.EndsWith("\\") == false) {
folderAssembly = folderAssembly + "\\";
}
string folderProjectLevel = System.IO.Path.GetFullPath(folderAssembly + "..\\..\\");
You can do it like this:
using System.IO;
Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, #"..\..\"));
use StackTrace
internal static class Extensions
{
public static string GetSourceDirectoryName(this Type type)
{
StackTrace stackTrace = new StackTrace(true);
foreach (var frame in stackTrace.GetFrames())
{
if (frame.GetMethod() is { } method && method.DeclaringType == type)
{
return Path.GetDirectoryName(frame.GetFileName());
}
}
throw new Exception($"未找到{type.Name}源文件目录");
}
}

NUnit is not failing test with dynamic keyword of .Net 4.0

I am using NUnit with Visual Studio Express Edition 2010 for C#, Now, normally test works fine. But whenever I try to use Massive.cs, which is open source api to access database. Test fails from that file only. Now, if I run the application, api is working fine. I have created a different library file to access data base.
I seriously don't understand the error. It is just giving error that object reference is not set to an object. But if I run the code, it works fine. I am using dynamic keyword as shown in link of api above. Does that making problem with NUnit ?
Is there any other way to test in this type of Scenarios?
Here are the further details of the code,
Test class is like this
dynamic item = new Item();
item.Insert(new { Name = "Maggi", Description = "Its 2 Min Nuddles", IsDelete = false });
var items = item.All();
Assert.AreEqual("Maggi", items.FirstOrDefault().Name);
Now, I have put test here. Which gives error like shown in image,
Now if I run code in console application, then code is working fine, code snippet is given below
dynamic item = new Item();
item.Insert(new { Name = "Maggi", Description = "Its 2 Min Nuddles", IsDelete = false });
var result = item.All();
foreach (var i in result)
{
Console.WriteLine(i.Name + i.Description);
}
Console.Read();
Here, code is working and same thing is not working with NUnit Test. Please have a look and help me out. Please let me know if any further information is needed from my side.
Most probable explanation is that you haven't set up your connection string in the test project.
If you are using NUnit, just put it in app.config of your test project.
Solved... There is a issue with NUnit Testing. It was not taking config file pefectly. So, I made two changes. Changes I have done in Project setting.
First change is to change Application Base to bin\debug just give application base as this and then config file to .config to .exe.config and things are up and running. :)

Categories

Resources