This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
.NET NUnit test - Assembly.GetEntryAssembly() is null
I'm writing a logging library. I want the library, by default, to write to a directory in the common application data folder named for the application. For example, if the application is called "MyApplication.exe", I want the data saved in "C:\ProgramData\MyApplication".
I'm using this code to construct the path:
private static string loggingDataPath =
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) +
Path.DirectorySeparatorChar +
Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().CodeBase) +
Path.DirectorySeparatorChar;
This works exactly as expected, with one problem. I can't unit test the library!
When I try to run the unit tests they all fail with a System.NullReferenceException. If I replace the "Assembly.GetEntryAssembly().CodeBase" call with a string the unit tests once again function properly.
I think I understand why this happens but I have no idea how to work around the problem. I hope someone will be able set me on the path of righteousness.
TIA!
UPDATE (5-24-12): I am not trying to unit test the contents of "loggingDataPath". The mere presence of the "Assembly.GetEntryAssembly().CodeBase" call causes ALL unit tests to fail with the above exception. Note that "loggingDataPath" is static (as it must be as this is a static library).
It's not only unit testing that will cause problems.
Given that GetEntryAssembly() can return null when a managed assembly has been loaded from an unmanaged application and also that CodeBase can contain a URL for assemblies downloaded from the Internet, and is not set for assemblies loaded from the GAC, I would avoid attempting this approach for a general-purpose logging library.
If that's not enough to convince you, other problems are (a) non-privileged users won't have write access to CommonApplicationData, and (b) multiple instances of your application attempting to write to the same log file will be a problem.
Instead, I would define the location of the log file in configuration.
Where would you suggest I put it to avoid this problem?
As I said, I would define it in configuration (e.g. an appSetting in app.config). This is the most flexible. If you want to put it under CommonApplicationData, you can use an environment variable that you expand using the Environment.ExpandEnvironmentVariables method when reading from the configuration file. For example:
<appSettings>
<add key="logFile" value="%ALLUSERSPROFILE%\MyApp\MyLogFile.log" />
...
</appSettings>
You still have to solve the problem of giving access to non-privileged users, and avoiding contention when accessing from multiple instances. You say your underlying logging library supports concurrent access, but be aware that this will have a potential performance cost, depending on how verbose your logging is.
Ignoring the sage advice of previous answers and addressing only my question, here is how I fixed the problem:
public static string LoggingDataPath {
get {
return loggingDataPath.Length > 0 ? loggingDataPath :
Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments) +
Path.DirectorySeparatorChar +
Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().CodeBase) +
Path.DirectorySeparatorChar;
}
set { loggingDataPath = value; }
}
This solution avoids initializing 'loggingDataPath' on the first access to the static class, thus avoiding the call to 'Assembly.GetEntryAssembly().CodeBase'.
Related
Like most web applications mine has static resources that must be part of the deployment or the user receives a 404 response from the server. My thought was to use unit testing to validate two things 1. the resource exists, and 2. the content was not modified. I have tried the following code but it expects (I think) that the files exist in the unit test project.
Solution structure:
WebApplicationProject
- ...
- public
- file.*
- otherfile.*
- web.config
WebApplicationProject.Tests
- AssetTests.cs
Am I going about this all wrong, should this not be part of a unit test and some other gait on the CI build process (Azure DevOps), or am I missing something super obvious? I'm likely asking the wrong questions and going about this the wrong way, because I know I'm not the first person to want to do something like this.
I've read other posts around testing with files, but they all are using test files to drive data for input in some method that consumes the file, or some process that generates a file for comparison. I don't want to do either of these things.
I have also played with the settings making the file an embedded resource, and to always deploy with the project, but the unit test project still cannot access the file the way I'm going about this.
[TestClass]
public class AssetTests
{
[TestMethod]
[DeploymentItem(#".\files\file.*")]
public void AwardLetters()
{
string path = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "file.*");// gets the working path for the testing dll, no files exist here.
Assert.IsTrue(File.Exists("file.*"), "FAIL: file {0} not found", "file.*");// nothing I have tried has access to the projects static resources
}
}
All results end in a file not found exception so far.
I did try to load the reference manually using:
Assembly a = Assembly.LoadFrom("WebApplicationProject");// also used WebApplicationProject.dll
This fails to find the reference. Yes, the reference property copy local is set to true.
I am open to all suggestions, but if you suggest that I have two copies of the files, please fully explain why this is desirable.
Alright here's my MVP. I'll leave this open for a while though in hopes someone has a better solution, it cant be this difficult to access the resources like this, I feel like there should be a way to access the applications directory without having to embed the file in the assembly just to pass it to a test method.
[TestMethod]
public void FileExists()
{
Assembly a = Assembly.LoadFrom(#"..\..\..\WebApplicationProject\bin\WebApplicationProject.dll");
string t = string.Join("", a.GetManifestResourceNames());
Assert.IsTrue(t.Contains("file.*"));
}
Now that I have the file I can also create a test to test the content of the file to validate it's contents.
I still think this is duck tape and it's not elegant at all. So please share your answers and critiques of my solution.
I have an app.config which is working fine.
But I also have a tool for automated testing, that runs some tests in environment without any file access. So I have to read a config file from string (or memory stream), but without mapping it physically because there is no access to file system from this automatic testing process.
In real life, of course, config file is stored somewhere, but for automated testing purposes I need some workaround to read a config file from string stored in memory. Is it even possible? I googled a lot, but the only thing I found is Save it as temp file and then read, but it's not my case.
Avoid a direct dependency from your class on app.config or any other file. Your class doesn't need app.config or Properties.Settings. It needs the values contained in the those files..
If you create a workaround for testing purposes then you're testing a different version of your class. That's the inherent problem - direct dependency on these files isn't testable. It doesn't mean that they're bad in some way or that we shouldn't use them, only that the class that requires the values should not read them from the file.
An ideal solution is constructor injection, a form of dependency injection. Provide the value to the class in its constructor and store it as a field. That way when the class is created it always has the values it needs.
At runtime you can use a dependency injection container - here's a walkthrough on setting one up for WCF. You're likely in a different project type, but the concepts still apply.
But for testing, it's as easy as creating a class and passing whatever value you want to use into the constructor. It's impossible to test with different values when the class reads from settings but it's easy using constructor injection.
Without the configuration file you'll have the default settings. You may override the default values:
Properties.Settings.Default["PropertyName"] = NewPropertyValue";
(Set the correct access modifier on your Settings class and use the correct namespace if it is in a library)
As first option I would go for Settings file in your case.
Even your user won't be ablle to access settings file content. Then it will return a default value for a particualr property.
You can try creaty a silly console app
static void Main(string[] args)
{
Console.WriteLine(Settings.Default.MyProperty);
Console.ReadLine();
}
were you set the your value for MyProperty on the Settings Tab of you Project Properties.
Then you can build your solution, open the binaries folder and delete your exe.config file and you will see that the app will be use default values.
As second option you can use command line arguments. could also be an option for you. (Here the article about some tricky case for command line arguments Backslash and quote in command line arguments )
Third option could be placing your file at c:\users\your app user \AppData\Roaming\YourAppName folder. here you should be granted for file access even for restricted user
For education reason I would also reccomend to look at this article: https://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k(ApplicationSettingsOverview);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5)&rd=true
Maybe you find the "Load Web Settings" option nice.
Another palce for investigation could be
I'm developing a class library and I need to provide a way to set configuration parameters. I can create a configuration section or I can expose static properties. My concern about static properties is security. What prevents a malicious component from making changes at runtime? For instance, in ASP.NET MVC you configure routes using a static property. Is this secure? Can a malicious component add/remove routes?
How would the "untrusted component" get in my application in the first place? NuGet for example. We don't know what's out there, who did it, and if it contains small bits of undesired state changes.
How would the "untrusted component" run? In ASP.NET all you need is PreApplicationStartMethodAttribute to run some code when the application is starting.
When you consider something as a security threat, you should also think about from whom you are trying to protect.
In order for "malicious code" to alter the values of your static properties, this code would need to be loaded into your AppDomain and run. Now think that a malicious attacker has managed to get his code to run in your AppDomain - are your static properties really your major concern? Such an attacker can probably do a lot worst.
Unless you have a scenario where you need to load an assembly/code originating from external untrusted sources, I think you don't really need to defend against your user accessing your properties (Not from security perspective anyway - usability is another thing).
EDIT - about external untrusted code
I still think this is not really your concern. If I understand correctly, you are developing and providing a library, to be used by some 3rd party in their application.
If the application owner decided to take some external library which he does not trust, add it to his application, and allow it to run, then this is not your concern, it is the application owner's concern.
In this scenario, everything I said above still applies. The malicious code can do much worse then setting your properties. It can mess with memory, corrupt data, flood the thread pool, or even easily crash the AppDomain.
The point is, if you don't own the application because you are only providing a class library, you don't need to defend from code running inside the AppDomain where you classes are loaded.
Note: Re. NuGet, I wouldn't be too worried about that. NuGet is sort of a static tool. If I understand correctly, it doesn't do things in runtime such as downloading code and running it. It is only used in design time to download binaries, add references, and possibly add code. I think it's perfectly reasonable to assume that an application owner that uses NuGet to download a package will do his due diligence to ensure that the package is safe. And he has to do it only once, during development.
As the previous answers note, there isn't really much of a difference here.
Malicious code could set a static property, and malicious code could change a configuration file. The latter is probably a bit easier to figure out from the outside, and can be done no matter what way the code is run (it wouldn't have to be .NET, wouldn't have to be run in your app domain, and indeed wouldn't have to be code, should someone gain the ability to change the file manually), so there's a bit of a security advantage in the use of a static property, though it's a rather bogus one considering that we may well have just moved the issue around a bit, since the calling code could very well be using configuration itself to decide what to set the properties to!
There's a third possibility, which is that you have an instance with instance members that set the properties, and it's the calling code that makes that instance static. This might be completely irrelevant to what you are doing, but it can be worth considering cases where someone might want to have your code running with two sets of configuration parameters in the same app domain. As a matter of security, it is much the same as the matter of static members, except that it could affect serialisation concerns.
So, so far there's the disadvantage of configuration files in that they can be attacked by code completely separate to yours, but with the noted caveat that the information might end up in a configuration file somewhere else anyway.
Whichever approach you take, the safety of access comes down to the way that you load in partially-trusted code.
The code should be loaded into its own app domain, and the security on that app domain set appropriately to how well it can be trusted. If at all possible, it shouldn't be your library that is doing so, but left to the calling code to decide upon the policies to be set by any partially-trusted code it loads in. Of course, if it's inherent to your libraries purpose that it loads in partially-trusted code, then it must do so, but generally it should remain agnostic as to whether the code is fully or partially trusted except in demanding certain permissions when appropriate. If it is up to your library to load in this code, then you will need to decide upon the appropriate permissions to give the app domain. Really, this should be the lowest amount of permission where it is still possible to do the job it was loaded in for. This would presumably not include FileIOPermission, hence preventing it from writing to a config file.
Now, whether your library or the calling code has loaded the partially trusted code, you need to consider what permissions are necessary on your exposed classes and their members. This covers the static setter properties, but would still be necessary if you took the config-file approach given that your scenario still involves that there is partially-trusted code accessing your library.
In some cases, the methods won't need any more protection, because they inherently have it due to what they do. For example, if you try to access a file but the calling code does not have permission to do so, then your code will fail with a security exception that will be passed up to the calling code. Indeed, you may have to do the opposite and take measures to allow the partially-trusted code to call your method (if you access a file in a way that is safe because the caller cannot affect which file is accessed or how, you may want to Assert file-access permissions at that point).
In other cases, you may need to add protection because calling code won't do anything that immediately attempts a security-restricted operation but which may cause trusted code to behave in an inappropriate manner. For example, if your code stores paths that are used by later operations, then essentially calling that code allows for file access to happen in a particular way. E.g.:
public string TempFilePath{get;set;}
public void WriteTempData(string data)
{
using(sw = new StreamWriter(TempFilePath, true))
sw.Write(data);
}
Here if malicious code set TempDirPath it could cause a later call by trusted code to WriteTempData to damage an important file by over-writing it. An obvious approach here is to call Demand on an appropriate FileIOPermission object, so that the only code that could set it would be code that was already trusted to write to arbitrary locations anyway (this could of course be combined by both restricting the possible values for TempDirPath and demanding the ability to write within the set of locations that allowed).
You can also demand certain unions of permission, and of course create your own permissions, though using unions of those defined by the framework has an advantage of better fitting in with existing code.
What prevents a malicious component from making changes at runtime?
This depends on the definition of "malicious component". Configuration is really intended to allow changes at runtime.
If you handle this via code (whether static or instance properties, etc), you do have the distinct advantage of controlling the allowable settings directly, as your property setter can control this however you wish. You could also add some form of security, if your application requires it, as you'd control the way this was set.
With a configuration section, your only control would be in reading the values - you couldn't control the writing, but instead would have to validate settings on read.
For sure, it can be changed by underlying classes which provide those abstractions, even in case of being defined as private members.
Think of a security interceptor that provision every request against defined privileges of authenticated or anonymous users.
I generally use Config file and Static variables together. I define static variable as private, and i make only "get" method to expose value. so it is can not be changed out of class.
I create a class to handle configuration implementing "IConfigurationSectionHandler" interface. My implementation is for ASP.NET Web applications.
Step 1: Create a section in web.config file to process later.
<configuration>
<configSections>
<section name="XXXConfiguration" type="Company.XXXConfiguration, Company"/>
...
</configSections>
<XXXConfiguration>
<Variable>Value to set static variable</Variable>
</XXXConfiguration>
...
<configuration>
Step 2: Create a class to handle previous configuration section.
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Xml;
using System.Configuration;
namespace Company{
public class XXXConfiguration : IConfigurationSectionHandler
{
/// <summary>
/// Initializes a new instance of LoggingConfiguration class.
/// </summary>
public XXXConfiguration() {}
private static string _variable;
public static string Variable
{
get {return XXXConfiguration._variable; }
}
public object Create(object parent, object configContext, XmlNode section)
{
// process config section node
XXXConfiguration._variable = section.SelectSingleNode("./Variable").InnerText;
return null;
}
}
}
Step 3: Use GetSection method of System.Configuration.ConfigurationManager at startup of application. In Global.asax
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
System.Configuration.ConfigurationManager.GetSection("LoggingConfiguration");
...
}
I have seen several developers perform:
string fileStore = Server.MapPath(#"~\someDirectory");
File.Create(fileStore + "someFileName.xxx");
I find that this makes unit testing difficult. Since I test with MSTest, there's no HTTP context, so this code just flat out fails.
Instead, I store my file paths in web.config.
string fileStore = ConfigurationManager.AppSettings["fileStore"];
This works with unit tests. Why do developers use Server.MapPath() in this way? Are there some benefits I'm unaware of?
I think both ways are perfectly valid.
Server.MapPath is more easily readable but is harder to test.
Keep in mind, though, that unit testing wasn't supported by ASP .NET at all (before the MVC thing).
Personally, I tend to create a directory service that gives me the paths:
public interface IDirectoryService {
string MapPath(string relative);
}
public DirectoryService : IDirectoryService {
public string MapPath(string relative)
{
return Server.MapPath(relative);
}
}
When I unit-test, I just mock it to returns something meaningful for the tests.
Server.MapPath() maps the specified relative or virtual path to the corresponding physical directory on the server. This will always be relative to the file that contains the code so there is no real room for error. You can always use an external file to store the "global variable", such as your web.config file in this case.
Either solution is viable, and there are likely plenty more out there. I think the biggest thing in this case would be which one better suits your needs.
When you don't control your own hosting environment it may be impossible to know the full path. You have to rely on Server.MapPath() in that aspect. Storing it in AppSettings assumes you know the full path up front.
I have a number of unit tests which rely on the presence of a csv file. They will throw an exception if this file doesn't exist obviously.
Are there any Gallio/MbUnit methods which can conditionally skip a test from running? I'm running Gallio 3.1 and using the CsvData attribute
[Test]
[Timeout(1800)]
[CsvData(FilePath = TestDataFolderPath + "TestData.csv", HasHeader = true)]
public static void CalculateShortfallSingleLifeTest()
{
.
.
.
Thanks
According to the answer in this question, you'll need to make a new TestDecoratorAttribute that calls Assert.Inconclusive if the file is missing.
Assert.Inconclusive is very appropriate for your situation because you aren't saying that the test passed or failed; you're just saying that it couldn't be executed in the current state.
What you have here is not a unit test. A unit test tests a single unit of code (it may be large though), and does not depend on external environmental factors, like files or network connections.
Since you are depending on a file here, what you have is an integration test. You're testing whether your code safely integrates with something outside of the control of the code, in this case, the file system.
If this is indeed an integration test, you should change the test so that you're testing the thing that you actually want tested.
If you're still considering this as a unit test, for instance you're attempting to test CSV parsing, then I would refactor the code so that you can mock/stub/fake out the actual reading of the CSV file contents. This way you can more easily provide test data to the CSV parser, and not depend on any external files.
For instance, have you considered that:
An AntiVirus package might not give you immediate access to the file
A typical programmer tool, like TortoiseSvn, integrates shell overlays into Explorer that sometimes hold on to files for too long and doesn't always give access to a file to a program (you deleted the file, and try to overwrite it with a new one? sure, just let me get through the deletion first, but there is a program holding on to the file so it might take a while...)
The file might not actually be there (why is that?)
You might not have read-access to the path
You might have the wrong file contents (leftover from an earlier debugging session?)
Once you start involving external systems like file systems, network connections, etc. there's so many things that can go wrong that what you have is basically a brittle test.
My advice: Figure out what you're trying to test (file system? CSV parser?), and remove dependencies that are conflicting with that goal.
An easy way would be to include an if condition right at the start of the test that would just execute any code in the test if the CSV file can be found.
Of course this has the big drawback that tests would be green although they haven't actually run and asserted anything.
I agree with Grzenio though, if you have unit tests that rely heavily on external conditions, they're not really helping you. In this scenario you will never really know whether the unit test ran successfully or was just skipped, which contradicts what unit tests are actually for.
In my personal opinion, I would just write the test so that they correctly fail when the file is not there. If they fail this is an indicator that the file in question should be available on the machine where the unit tests run. This might need some manual adjustments at times (getting the file to the computer or server in question), but at least you have reliable unit tests.
In Gallio/MbUnit v3.2 the abstract ContentAttribute and its concrete derived types (such as [CsvData] have a new optional parameter that allows to change the default outcome of a test in case of an error occured while opening or reading the file data source (ref. issue 681). The syntax is the following:
[Test]
[CsvData(..., OutcomeOnFileError = OutcomeOnFileError.Inconclusive)]
public void MyTestMethod()
{
// ...
}