chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
How TypeMock can help get rid of the dependency of harddrive in unit test please?

For example: in "d:" I have three ".txt" files and two ".bmp" files. So in my test case, I wrote:
string [] strArr = KY_Utility.GetFilesSinglePattern( @"D:","*.txt");
Assert.AreEqual(3, strArr.Length);

it will pass. However, some day, if I delete some .txt files, red bar will appear even though my code has never been modified.

So, I am wondering if TypeMock can rescue in this sitution. :?:


---------------------------------------------------------------------
Target code(Code is tested):

public static string[] GetFilesSinglePattern ( string pathName, string pattern )
{
StringCollection coll = new StringCollection();
string[] files = Directory.GetFiles(pathName, pattern);
coll.AddRange(files);
string[] arr = new string[coll.Count];
coll.CopyTo(arr, 0);
return arr;
}
asked by kyue (4.6k points)

7 Answers

0 votes
8) This is actually a nice example where TypeMock can help.

:idea: But beforehand I will explain a way to do this without TypeMock.
What you do is create a new directory in you test project (suppose we call it ' estFiles') that contains the files that you expect to have (three ".txt" files and two ".bmp" files).
Then you can test the GetFilesSinglePattern by directing the method to the test directory:
string[] strArr = KY_Utility.GetFilesSinglePattern( @"....	estFiles","*.txt"); 

This way your tests are self contained and are not effected by external dependencies.

:arrow: When KY_Utility.GetFilesSinglePattern is called from within your tested code, we still don't want to be dependant on external resources but the 'pathName' argument is something that we might not have control over. Here is where TypeMock helps.

:arrow: To do this we can SWAP the argument values andrun the method as normal (seeNatural Mocks too).

Here is how to do it in your example:
Mock KY_UtilityMock = MockManager.Mock(typeof(KY_Utility));
UtilityMock.ExpectUnmockedCall("GetFilesSinglePattern").Args(new Assign(@"....	estFiles"),new Assign("*.txt"));


or in NaturalMocks
using (RecordExpectations recorder = RecorderManager.StartRecording())
{
   KY_Utility.GetFilesSinglePattern(null,null);
   recorder.CallOriginal.CheckArguments(new Assign(@"....	estFiles"),new Assign("*.txt"));
}


:idea: This is a pattern that we used many times to verify configuration files.
We had to verify how the code behaves when the file is non existent/corrupt etc...
answered by scott (32k points)
0 votes
Thanks to Scott for quick reply.

I am still a little bit confused :? Maybe we are mocking out differnet thing :?:

Assume: In a test without TypeMock, I can have five files on hard drive which are "a.txt, b.txt, c.txt, a.bmp, b.bmp".

Then using TypeMock, I don't need to worry about the first parameter, path "D:", also I just mock out "GetFilesSinglePattern()" , set up the expectation returned as strArr, which includes "a.txt, b.txt, c.txt". Then the string array returned, strArr, can be consumed by other objects in test cases.

However my test case still want to test the second parameter, " *.txt " will work for me to filter five file names and just return 3 files, "a.txt, b.txt, c.txt", as I tested as follows( Does this test too much? :wink: ):
string [] strArr = KY_Utility.GetFilesSinglePattern( @"D:","*.txt");
Assert.AreEqual(3, strArr.Length);


Can TypeMock help this please? I am just trying to mock there are 5 file names, "a.txt, b.txt, c.txt, a.bmp, b.bmp". Then my test case will consume them for checking there are 3 ".txt" indeed. Then pass my test case without bothering real files on disk. :shock:
answered by kyue (4.6k points)
0 votes
Ok,
I would create a test directory within the test project and to run KY_Utility.GetFilesSinglePattern on that directory.
KY_Utility.GetFilesSinglePattern( @"....	estFiles","*.txt");

This will actually read the disk. I wouldn't mock anything as this will test that the mocks are ok and not the actual method.
answered by scott (32k points)
0 votes
Answer is accepted and appreciative.

Thanks
answered by kyue (4.6k points)
0 votes
Another solution for this problem may lie in the fact that
Then pass my test case without bothering real files on disk.

If no hard drive access is required and the files are not going to be opened later on during the testing you could just mock the Directory.GetFiles(pathName, pattern) call inside the GetFilesSinglePattern method.

An example of the test code follows:
Mock directoryMock = MockFactory.Mock(typeof(System.IO.Directory));
string[] retArray = { "a.txt", "b.txt", "c.txt", "a.bmp", "b.bmp" };
directoryMock.ExpectAndReturn("GetFiles", retArray);

string[] strArray = KY_Utility.GetFilesSinglePattern( @"D:","*.txt");
Assert.AreEqual(3, strArray.Length);


Hope this helps :)
answered by Paul (1.2k points)
0 votes
Thanks to Paul for help.

IMHO, your code is what I dreamed about :wink: , however, there are two problems.

First, is there a "MockFactory" class in TypeMock please? I never used it. Or you are using another framework?
Second, I guess that the TypeMock can not mock "System.IO.Directory", which is from MS core lib.

My code as follows:
[Test]
public void Test_GetFilesSinglePattern_TypeMock()
{
   MockObject directoryMock = MockManager.MockObject(typeof(System.IO.Directory));// ***this line get ERROR
   string[] retArray = { "a.txt", "b.txt", "c.txt", "a.bmp", "b.bmp" }; 
   directoryMock.ExpectAndReturn("GetFiles", retArray); 

   string[] strArray = KY_Utility.GetFilesSinglePattern( @"D:","*.txt"); 
   Assert.AreEqual(3, strArray.Length); 
}


Anyway, it gets error during running.

FileRenamer.Test_KY_Utility.Test_GetFilesSinglePattern_TypeMock : TypeMock.TypeMockException :
*** Cannot mock types from mscorlib assembly.


Thanks again.
answered by kyue (4.6k points)
0 votes
Kyue,

I should always test the solution prior to posting :oops:

The MockFactory was a typo as I meant MockManager as per your example. I have found no other mock framework that provides the flexability and functionality that TypeMock offers :)

When I perform the test I get the same error as you. Scott has mentioned in previous posts the mscorlib mocking is currently being developed and will be available in future releases :D thou this does not help your immediate problem :(

We are thus back to Scott's suggestions. You could include automatic environment creation for your tests to fix the file removal problem. Here is an example of the test code:
// Determine the path where the test files will be located
string testFileLocation = Environment.CurrentDirectory + @"TestFiles";

// Determine if the test directory exists and remove it
if (Directory.Exists(testFileLocation))
   Directory.Delete(testFileLocation, true);

// Create the directory and add the files
Directory.CreateDirectory(testFileLocation);
using (File.Create(testFileLocation + @".txt")) { }
using (File.Create(testFileLocation + @".txt")) { }
using (File.Create(testFileLocation + @"c.txt")) { }
using (File.Create(testFileLocation + @".bmp")) { }
using (File.Create(testFileLocation + @".bmp")) { }

// Perform test
string[] strArray = KY_Utility.GetFilesSinglePatter(testFileLocation, "*.txt");
Assert.AreEqual(3, strArray.Length);


Sorry that my solution lead you in the wrong direction
answered by Paul (1.2k points)
...