VS2008: File creation fails randomly in unit testing? - c#

I'm working on implementing a reasonably simple XML serializer/deserializer (log file parser) application in C# .NET with VS 2008. I have about 50 unit tests right now for various parts of the code (mostly for the various serialization operations), and some of them seem to be failing mostly at random when they deal with file I/O.
The way the tests are structured is that in the test setup method, I create a new empty file at a certain predetermined location, and close the stream I get back. Then I run some basic tests on the file (varying by what exactly is under test). In the cleanup method, I delete the file again.
A large portion (usually 30 or more, though the number varies run to run) of my unit tests will fail at the initialize method, claiming they can't access the file I'm trying to create. I can't pin down the exact reason, since a test that will work one run fails the next; they all succeed when run individually.
What's the problem here? Why can't I access this file across multiple unit tests?
Relevant methods for a unit test that will fail some of the time:
[TestInitialize()]
public void LogFileTestInitialize()
{
this.testFolder =
System.Environment.GetFolderPath(
System.Environment.SpecialFolder.LocalApplicationData
);
this.testPath = this.testFolder + "\\empty.lfp";
System.IO.File.Create(this.testPath).Close();
}
[TestMethod()]
public void LogFileConstructorTest()
{
string filePath = this.testPath;
LogFile target = new LogFile(filePath);
Assert.AreNotEqual(null, target);
Assert.AreEqual(this.testPath, target.filePath);
Assert.AreEqual("empty.lfp", target.fileName);
Assert.AreEqual(this.testFolder + "\\empty.lfp.lfpdat", target.metaPath);
}
[TestCleanup()]
public void LogFileTestCleanup()
{
System.IO.File.Delete(this.testPath);
}
And the LogFile() constructor:
public LogFile(String filePath)
{
this.entries = new List<Entry>();
this.filePath = filePath;
this.metaPath = filePath + ".lfpdat";
this.fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1);
}
The precise error message:
Initialization method
LogFileParserTester.LogFileTest.LogFileTestInitialize
threw exception.
System.IO.IOException:
System.IO.IOException: The process
cannot access the file
'C:\Users\<user>\AppData\Local\empty.lfp'
because it is being used by another
process..

You should be mocking the file system access, and not actually reading/writing files in your unit tests.

Sounds like some of the tests are being run at the same time. Do the individual tests write to the file, or just read it? If they're read only, I'm sure we can make a minor change to enable them to run concurrently. More details?

Related

How to have Console mirror output from FileStream?

I want to be able to have a FileStream output to the Console for testing purposes.
[TestMethod]
public void LoggerSetStreamConsole ( ) {
logManager.WriteLine("LoggerSetStreamConsole: adding logger {0}", Name);
logger = logManager.Add(this);
Console.SetIn(new StreamReader(logger.LogStream));
logger.WriteLine("This is a test of the local logging system writing to the Console.");
logManager.WriteLine("LoggerSetStreamConsole: removing logger {0}", Name);
logManager.Remove(this);
}
logger.LogStream is a FileStream. Is this correct? Since this is running in the MSVS unit testing environment, whenever the code has Console.Write(...) there is output in the test results. That is ultimately what I am looking for.

Is it possible that HttpServerUtility.MapPath locks the file?

Two functions in our standard ASP.NET app are:
private static void SaveToFileSystem(AttributeFileAttachment attach, int paId)
{
string fileName = GetAttachmentFullName(attach.FileName, paId);
File.WriteAllBytes(fileName, attach.Content);
}
public static string GetAttachmentFullName(string name, int paId)
{
HttpContext ctx = Util.Util.GetHttpContext();
return string.Format("{0}{1}_{2}_{3}",
ctx.Server.MapPath("<some variable to get the path>" + "attributeFileAttachments\\"),
ctx.Session.SessionID,
paId,
name);
}
when File.WriteAllBytes is executed it returns exception:
he process cannot access the file '\\d$\Home\\attributeFileAttachments\' because it is being used by another process.
The essence are two lines:
ctx.Server.MapPath... (Microsoft code)
and File.WriteAllBytes...
that work on the same file.
It turns out that HttpServerUtility.MapPath locks the file and leaves it locked !?
I don't see any comments on that in official documentation nor I see anybody complains on that.
But it can't be anything else, since the two lines are consecutive.
When I modify fileName for File.WriteAllBytes in immediate window just a bit, the writing succeeds, since that new file is not locked.
One more thing I have noticed is that this happens only and always for some of the attachment files.
Thank you for the time and any advice.

Upload Image to Cloud UnitTest

I am trying to upload an image to a cloud and i want to be able to test this,
here is what i have tried already, I dont really understand fully what im doing, so if somebody could tell me what to do, I would appreciate it.
I have included the main method for this and the test of that method so far.
public static String UploadToCloud(string fileName)
{
try
{
SetUpConnection();
#region Upload a File from local storage to the Cloud
// Get a reference to the blob.
blob = blobContainer.GetBlobReference("Images/" + fileName.Substring(fileName.LastIndexOf('\\')));
blob.UploadFile(fileName);
return blob.Uri.ToString();
#endregion
}
catch (StorageClientException e)
{
Console.WriteLine("Storage client error encountered: " + e.Message);
return "Upload failed";
}
}
/// <summary>
///A test for UploadToCloud
///</summary>
[TestMethod()]
public void UploadToCloudTest()
{
string fileName = "https://kevin.blob.core.windows.net/cp300/Images//skin-mole.jpg";
Image expected = Image.FromFile(#"C:\Users\Public\Pictures\Sample Pictures\skin-mole.jpg");
string actual;
actual = CloudConnection.UploadToCloud(fileName);
//Compares to images and checks they are exactly the same
MemoryStream ms = new MemoryStream();
expected.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
String expectedBitmap = Convert.ToBase64String(ms.ToArray());
ms.Position = 0;
actual.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
String actualBitmap = Convert.ToBase64String(ms.ToArray());
Assert.AreEqual(expectedBitmap, actualBitmap);
//Assert.AreEqual(expected, actual);
//Assert.Inconclusive("Verify the correctness of this test method.");
}
I'd say that this isn't really a unit test -- you're trying to upload something to an external service that you have no control over and can't guarantee that the results are going to be the same from run to run.
What you've written is an integration test, which is a test of how two or more software components work together. In this case, the two components are
Your code
The cloud upload API
There's nothing wrong with integration tests, but they tend to be slower (in this case, due to uploading a file to the cloud), and they tend to be more brittle. Your integration test, for example, would break if the cloud service wasn't available. Nothing changed in your code, nothing changed in your test, but the test's results were different.
If you wanted to unit test your UploadToCloud method, I'd recommend that you start by wrapping your "cloud uploading" functionality in a class that implements an interface, e.g. ICloudUploader. Then you can mock out the pieces that actually communicate with your cloud service, and ensure that the functionality of your code is correct under all of the situations you want to test (successful upload, service is unavailable, upload fails due to file being too big, whatever).
For mocking out a class, you can either roll your own (write a class that implements your interface, for example public class FakeCloudUploader : ICloudUploader, or look into a mocking framework like Moq or RhinoMocks.
As for the test method you provided, it's not really testing the output of the method. It should validate that the string you get back from UploadToCloud is the value you expected.

Why multiple log files are getting created with GUID using System.Diagnostics c# [duplicate]

I use TextWriterTraceListener (System.Diagnostics) in my application to trace several things like exceptions,...
The application is running on a terminal server and if there are many users using it simultaneously the listener starts to create many tracefiles with random GUIDs in the filename.
Are there possibilities or workarounds to avoid this behaviour ?
I've just taken a look at the documentation for TextWriterTraceListener and there's a note about 1/3 of the way down the page
If an attempt is made to write to a file that is in use or unavailable, the file name is automatically prefixed by a GUID
So, this would appear to be by design. If the file is indeed unavailable then there's nothing that can be done about it with the current implementation. What you could try doing is writing a custom implementation of TextWriterTraceListener that overrides the relevant Write/WriteLine methods so that the output goes to a file, per user, with a name that better suits your needs.
If what you want is for ALL logging from ALL users on the Terminal Server to go to a single file, then you'll almost certainly need to have some kind of "3rd party" process running that "owns" the file and synchronises writes to it, such as a Windows Service that is then called by your custom TextWriterTraceListener
Was the fix calling the Trace.Listeners.Add(xxx listener) multiple times on accident?
Because if you have multiple listeners added they write too all listeners when you call the Trace.writeline();
Also local IIS might be continueing to have the file in use when you shut down the application.
I am currently testing the addition of System.Diagnostics.Trace.Listeners.Clear() in my output method...
// Upon a new day re-create the TextWriterTraceListener to update our file name...
if (_date?.Day != DateTime.Now.Day) { _listener = null; }
if (_listener == null)
{
System.Diagnostics.Trace.Listeners.Clear();
_fileName = $"{DateTime.Now.ToString("yyyy-MM-dd")}_Trace.json";
// Add a writer that appends to the trace.log file:
_listener = new System.Diagnostics.TextWriterTraceListener(_fileName);
_listener.IndentSize = 4;
_listener.TraceOutputOptions = System.Diagnostics.TraceOptions.None; // TraceOptions.DateTime | TraceOptions.ThreadId;
System.Diagnostics.Trace.AutoFlush = true;
System.Diagnostics.Trace.Listeners.Add(_listener);
// Obtain the Console's output stream, then add that as a listener...
System.Diagnostics.Trace.Listeners.Add(new System.Diagnostics.TextWriterTraceListener(Console.Out));
}

File.Delete error "The process cannot access the file because it is being used by another process"

I have written a DotUnit test suite for testing some data import functionality in my application. It works by making a backup of some local Microsoft Access Database, let's call it 'Test.mdb', to 'Test.mdb.bak', performing some data import (and subsequent Assert checks) and then restoring the original from the backup.
The SetUp() function creates a backup if one doesn't exist.
The TearDown() function attempts to delete 'Test.mdb' and then copy 'Test.mdb.bak' to 'Test.mdb'.
Intermittently running the tests fail with this error "The process cannot access the file because it is being used by another process".
I've had a look the MSDN on File.Delete and IO permissions but couldn't find what I was after. Does anyone know if there is a .NET feature that will allow me to completely lock the file before attempting to delete it? Or find which process is accessing it at the time of deletion?
I had a similar issue while unit testing Entity Framework code using a SQLite database where each test needed to use a fresh instance of a database, so my the [TestCleanup] method was doing a File.Delete on the database, but was getting the same "used by another process" error.
Before I called, File.Delete, I had to add the following to fix my issue.
GC.Collect();
GC.WaitForPendingFinalizers();
[TestInitialize]
public void MyTestInitialize()
{
// Copies the embedded resource 'MyDatabase.db' to the Testing Directory
CommonTestFixture.UnpackFile("MyDatabase.db", this.GetType(), this.TestContext.TestDeploymentDir);
}
[TestCleanup]
public void MyTestCleanup()
{
// Adding the following two lines of code fixed the issue
GC.Collect();
GC.WaitForPendingFinalizers();
// Removes 'MyDatabase.db' from the testing directory.
File.Delete(Path.Combine(this.TestContext.TestDeploymentDir, "MyDatabase.db"));
}
[TestMethod]
public void GetVenueTest()
{
// CreateTestEntities() is a helper that initializes my entity framework DbContext
// with the correct connection string for the testing database.
using (var entityFrameworkContext = CreateTestEntities())
{
// Do whatever testing you want here:
bool result = entityFrameworkContext.TestSomething()
Assert.IsTrue(result);
}
}
You might reconsider your testing approach. Instead:
Create a temporary copy of the file
Perform the actions that are being tested on the temp file
Release all handles (close all connections) to the temp file
Delete the temp file
Using this pattern, the only process that will be accessing the file will be the thread running the unit test.
Use the function: System.IO.Path.GetTempFileName();
http://msdn.microsoft.com/en-us/library/system.io.path.gettempfilename.aspx
EDIT: Here is one way to code it:
var tempFile = System.IO.Path.GetTempFileName();
System.IO.File.Copy(#"C:\Test.mdb", tempFile, true);
// 2. Test tempFile
// 3. Release handles to tempFile, use a using statement around any
// streams or System.IO API's that are using the file in any way.
System.IO.File.Delete(tempFile);
These two lines solve the issue.
GC.Collect();
GC.WaitForPendingFinalizers();
I have tested this in my code and it worked well.
--- Jeetendra

Categories