Should GetEnvironmentVariable work in xUnit tests? - visual-studio

If I set environment variables for a .Net Core web project in Visual Studio 2017 using the project properties page, I can read the value of the variable using Environment.GetEnvironmentVariable; however, when I set the environment variable for my xUnit testing project and then debug the test, Environment.GetEnvironmentVariable always returns null. Is there something about the fact that it is a testing project that should prevent the variable from being used the same as with the web project? If so, is there a way that I can set the environment variables for a test project? Thank you.

The GetEnvironmentVariable works fine in xUnit tests. The problem is to properly set a variable. If you set the variable at Properties -> Debug page, then the variable is written to Properties\launchSettings.json and Visual Studio makes all work to launch an application with the selected profile. As you could see, launchSettings.json even isn't copied to output folder by default. It's impossible to pass this file as argument to dotnet run or dotnet test, that leads to obvious problem if tests are run automatically on a CI server. So it is not surprising that launchSettings.json isn't considered by a test runner.
Solution: there are a lot of ways to setup a test environment in xUnit:
Constructor
Base class
Fixture
For example, this collection fixture sets up all environment variables from launchSettings.json:
public class LaunchSettingsFixture : IDisposable
{
public LaunchSettingsFixture()
{
using (var file = File.OpenText("Properties\\launchSettings.json"))
{
var reader = new JsonTextReader(file);
var jObject = JObject.Load(reader);
var variables = jObject
.GetValue("profiles")
//select a proper profile here
.SelectMany(profiles => profiles.Children())
.SelectMany(profile => profile.Children<JProperty>())
.Where(prop => prop.Name == "environmentVariables")
.SelectMany(prop => prop.Value.Children<JProperty>())
.ToList();
foreach (var variable in variables)
{
Environment.SetEnvironmentVariable(variable.Name, variable.Value.ToString());
}
}
}
public void Dispose()
{
// ... clean up
}
}
Set Copy to output directory: Always for launchSettings.json to make the file accessible from tests.

A solution for using environment variables in unit tests, for either mstest or xunittest, is through the ".runsettings" file provided for the platform:
UPDATE:
This works only for mstest.
Add a file with .runsettings extension in the project:
Configure environment variables in file "xxx.runsettings" created:
<!-- File name extension must be .runsettings -->
<RunSettings>
<RunConfiguration>
<EnvironmentVariables>
<!-- List of environment variables we want to set-->
<VARIABLE_XXXX>value X</VARIABLE_XXXX>
<VARIABLE_YYYY>value Y</VARIABLE_YYYY>
</EnvironmentVariables>
</RunConfiguration>
</RunSettings>
Add RunSettingsFilePath tag in test .csproj pointing to the .runsettings file.
Important: the path is absolute.
Using $(MSBuildProjectDirectory) variable will return the absolute path to the project diretory.
Another options to use .runsettings are in link below:
https://learn.microsoft.com/pt-br/visualstudio/test/configure-unit-tests-by-using-a-dot-runsettings-file?view=vs-2019

Great thread helped me find the adapted solution for me.
I needed something that works well for local dev / tests (using VS code) JSON file works fine.
I also needed something that can be used with CI/CD and deployment; environment variables were needed.
My fixture class needs the environment variable to be able to run the tests in the different environments.
I'm using the same principle #Ilya Chumakov except with System.Text.Json (in 2022 using .NET 6...)
I thought that sharing it might help save other people some time:
if (File.Exists(Directory.GetCurrentDirectory()+"/local.settings.json")){
using var file = File.Open(Directory.GetCurrentDirectory()+ "/local.settings.json",FileMode.Open);
var document = JsonDocument.Parse(file);
var variables = document.RootElement.EnumerateObject();
foreach(var variable in variables){
Environment.SetEnvironmentVariable(variable.Name, variable.Value.ToString());
}
}
All the needed variables are at the root of the local.settings.json. adapt if you use it for a lot of things, easy to add an "env" property which contains all your environment variable and just read from it.
For those who use VS code like me. Don't forget to add to your .csproj:
<ItemGroup>
<Content Include="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
Took me also a bit of tinkering to find that out.

Related

How to use different properties file or environment profiles to execute a maven project?

I am building an automation framework to test a web application in 2 separate environments namely stage and test.
I am storing environment variables like "user_names" and "application_URL" which are unique to the environments in a property file which is read by the test scripts.
Since I have two different environments, i want to execute the same tests in both of them by having two separate profiles of environment variables files.
I have first environment properties file as below:-
browser = Chrome
admin_Url = https://stage-some-website/login
Username = adminuser1
Password = adminuserpw1
DatabaseURl=""
DatabasePasswords=""
This file is read by below base case which will initialize the browsers and read this property file.
public static WebDriver driver;
public static Properties read_propertyFile;
String PropertyFilePath = "\\src\\test\\java\\com\\resources\\Environment.properties";
If i make another property file for second environment, how can i use it ?
Can i parameterize which property file is being read by the base case and pass the filename or environment name in the command that executes the maven project ?

Build Gradle getProperties before running already made task

I’m trying to use a Java, Serenity-BDD project with gradle version 4.8+, but the application is not pulling the CLI arguments of -Denvironment and -Dservicebranches. I have these properties as blank values in my local.properties file, and they’re not getting assigned when my app runs.
./gradlew --build-cache build -Dwebdriver.remote.url=${SELENIUM_REMOTE_URL} -Denvironment=${ENVIRONMENT} -Dservicebranches=${SERVICE_BRANCHES} -Dtags=${TAGS}
I have a local.properties file with properties that are being successfully dependency injected into the project (through Serenity-Spring). I'm hoping that these CLI arguments will override these values:
servicebranches=
environment=local
But right now, anything specified in the CLI arguments are not being passed into the project. Either through DI, or through explicitly grabbing the environment variables in the build.gradle, which what I've tried hasn't been working.
Here's a few things which I have tried in the build.gradle:
//task integrationTests() {
// doFirst
// {
// def environment = System.getProperty('environment')
// def servicebranches = System.getProperty('servicebranches')
// }
// tasks.build.execute()
//}
//integrationTests.dependsOn(build)
//build.doFirst{
// systemProperties System.properties
// def environment = System.properties['environment']
// environment = environment //This actually flags with 'Silly assignment'
//}
build.doFirst{
def environment = System.getProperty('environment')
def servicebranches = System.getProperty('servicebranches')
}
The latest one seems to still be missing a step, because the program is still working, but the args are still not getting through. I've even tried -Denvironment=potato, and no errors have come up because I do not have a property or properties file named that.
I've also tried using the -P tag instead of -D tag, but that doesn't seem to be working either.
All I’m trying to do is use build.gradle to use System.getProperty(‘environment’) and System.getProperty(‘servicebranches’) before I use the already created ‘build’ task that comes with Serenity. How would I do this? Do I build a whole new task, where I use these getProperties, and then call the build task? Do I have to specify the assignment of these same named variables in the local.properties file?
-D is for system properties in Gradle. Try with -P instead (https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties)
I know this is a very old question but here's what I did to solve my problem, I got the idea from here: https://github.com/serenity-bdd/serenity-documentation/pull/120/files
Serenity was not pulling the environment from gradle to use EnvironmentSpecificProperties, it kept saying "undefined property for environment 'null" when I removed the default environment. I had to add this to my Gradle file:
test {
systemProperty 'environment', System.properties['environment']
}

sonar c# eco system: how to specify diffent binaries folder

I am actually evaluate sonar (sonarsource.org) for using it with c#.
Is it possible to specify a different binaries folder (MsBuild OutDir Property) for csharp projects? I use a custom OutDir on our build server to have the binaries/Buildoutput of every csharp project in one place.
Tried (with java runner and sonar-project.properties)
binaries=Binaries
And
sonar.gendarme.assemblies=Binaries/*.*
sonar.fxcop.assemblies=Binaries/*.*
BTW: how to specify search paths for gallio code coverage? My test assemblies are also not in bin/Debug.
Any Ideas?
Found out that wild cards aren't possible. But: should the path to the assembly be relative or absolute? Relative...
File basedir = (vsProject == null) ? solution.getSolutionDir() : vsProject.getDirectory();
...
File file = new File(basedir, filePath);
But still no success with
sonar.fxcop.assemblies=../Binaries/Assembly1.dll;../Binaries/Assembly2.dll

How do I save files to $(PROJECT_DIR) from objective-c code?

I have code which generates resources which I want to save in a subdirectory of my $(PROJECT_DIR).
How do I get the real path from this environment variable in code?
open the projects build settings and add SAVEPATH=#\"$(PROJECT_DIR)\" to the preprocessor macros.
Then you can get the project directory like this:
NSString *projectDir = SAVEPATH;
I'm not sure if Xcode 3.2.6 has changed the way that () are used with environment variables, but I've found that using the following pre-processor macro works for me (#fluchtpunkt's answer gives me a compiler error):
PROJECT_DIR=#\""$PROJECT_DIR"\"
Then I can do:
NSString *savePath = [PROJECT_DIR stringByAppendingPathComponent:#"Save Folder"];

Project (bin) folder path at compile time?

Is there a way to find out the project path at compile time?
I want to create a unit test that tests if the configurartion in the default web.config (the one in the project folder). Mainly to reduce human error.
I cannot rely on assembly locations at runtime (for the test), so I need to know where the project folder is to access web.config there.
I need a "generic" solution since I'd like to use the same (base) test code for multiple projects, and the physical location is different anyway for most development machines.
Thanks.
Based on rkb's answer,
As it sounds like you've got a C# project, use this post build step.
echo namespace ProjectPath { static public class ProjectPath { public static readonly string Path = #"$(ProjectDir)";} } > $(ProjectDir)path.cs
Then include path.cs as an existing item to your test project. Then you can access it via:
string path = ProjectPath.ProjectPath.Path;
If you want the Visual Studio project path, at compile time, you could use a Pre-Build Event (see the Project Properties dialog) to run a command line that will create a source file used in your project.
The source file will contain some code, say a variable definition. Your testing code uses this variable. The value of the variable will come from VS; when it runs your Pre-Build Event command, it substitutes project properties for certain macros. The macro you want is probably ProjectDir.
So in the end, you have something like this for your Pre-Build Event's command:
echo 'const char * PROJECT_PATH = "$(ProjectDir)";' > source.cpp
Not sure what language you're using, so adjust accordingly.
To improve the solution slightly, instead of using the Post Build Event Command Line, you can run the command as an MSbuild Exec Task in the BeforeBuild Target of the project.

Resources