0

I have this piece of code that counts the amount of instances a phrase exists within a text file. When I call this from a main() function, it works as expected.

When I try to write a Unit Test for it, it fails upon opening the file, returning -1 (see code below).

Here is the code for my countInstances function:

int countInstances(string phrase, string filename) {
    ifstream file;
    file.open(filename);
    if (file.is_open) {
        stringstream buffer;
        buffer << file.rdbuf();
        file.close();
        string contents = buffer.str();

        int fileLength = contents.length();
        int phraseLength = phrase.length();
        int instances = 0;

        // Goes through entire contents
        for(int i = 0; i < fileLength - phraseLength; i++){
            int j;

            // Now checks to see if the phrase is in contents
            for (j = 0; j < phraseLength; j++) {
                if (contents[i + j] != phrase[j])
                    break;
            }

            // Checks to see if the entire phrase existed
            if (j == phraseLength) {
                instances++;
                j = 0;
            }
        }

        return instances;
    }
    else {
        return -1;
    }
}

My Unit Test looks like:


namespace Tests
{       
    TEST_CLASS(UnitTests)
    {
    public:
        TEST_METHOD(CountInstances) {
            /*
                countInstances(string, string) :
                countInstances should simply check the amount of times that
                the passed phrase / word appears within the given filename
            */
            int expected = 3;
            int actual = countInstances("word", "../smudger/test.txt");
            Assert::AreEqual(expected, actual);
        }
        };
}

For the CountInstance Test I get the following message:

Message: Assert failed. Expected:<3> Actual:<-1>

Any ideas on where my issue comes from and how I could go about fixing it? Thanks.

  • 3
    The test binaries are probably not executed from a directory where it can find the in-data file that you open using a relative path: `"../smudger/test.txt"`. – Ted Lyngmo Apr 11 '19 at 17:50
  • Okay, thanks for the response. Could you please elaborate on how to go about fixing this? – FreakyWeeks Apr 11 '19 at 18:04
  • 1
    The simplest way would be to find where the test binaries are and to calculate the relative path to `text.txt` from them to use that instead. – Ted Lyngmo Apr 11 '19 at 18:14

2 Answers2

0

The fact that your tests depend on some file to be present in the file system makes your tests hard to maintain and understand, because the information for each test case is distributed. If you change the directory layout later, the tests may then fail again.

A better way to unit-test your code would be to extract the reading of the file content into a function of its own which, for example, returns the string with the file's content. For a start, put that function in a separate file.

In your tests you can then replace that function with a mock: The mock returns a string, but does not read it from a file - instead, your test code provides the string which the function shall then return. Since the original function was put into a separate file, you can create the test executable by not linking the original function, but the mocked function instead.

This way, you are in your tests not dependent on the file system. You can easily create a large number of test cases and have everything under control from within the test code.

There are more advance ways to achieve this, but this answer is just meant to give you a starting point. If you want to find out more, search for dependency injection, mocking, inversion of control.

Dirk Herrmann
  • 5,550
  • 1
  • 21
  • 47
0

Although having file system dependencies in unit tests is not ideal, you could simply create the unit test DLL(s) in a folder containing the test data files.

enter image description here

Chris Olsen
  • 3,243
  • 1
  • 27
  • 41