I know that it's strongly recommended to run unit-tests in separation from file system, because if you do touch file system in your test, you also test file system itself. OK, that's reasonable.
My question is, if I want to test file saving to the disk, what do I do? As with database, I separate an interface that is responsible for database access, and then create another implementation of this for my tests? Or may be there's some other way?
There is a general rule to be cautious of writing unit tests that do file I/O, because they tend to be too slow. But there is no absolute prohibition on file I/O in unit tests. In your unit tests have a temporary directory set up and torn down, and create test files and directories within that temporary directory.
By convention, Go testing files are always located in the same folder, or package, where the code they are testing resides. These files are not built by the compiler when you run the go build command, so you needn't worry about them ending up in deployments.
The tester must determine from the results whether the unit has passed or failed the test. If the test is failed, the nature of the problem should be recorded in what is sometimes called a test incident report (see Chapter 7). Differences from expected behavior should be described in detail.
My approach towards this is heavily biased on the Growing Object-Oriented Software Guided by Tests (GOOS) book that I just read, but it's the best that I know of today. Specifically:
Update for commenter:
If you're reading structured data (e.g. Book objects) (If not substitute string for IEnumerable)
interface BookRepository { IEnumerable<Books> LoadFrom(string filePath); void SaveTo(string filePath, IEnumerable<Books> books); }
Now you can use constructor-injection to inject a mock into the client class. The client class unit tests therefore are fast ; do not hit the filesystem. They just verify that the right methods are called on the dependencies (e.g. Load/Save)
var testSubject = new Client(new Mock<BookRepository>.Object);
Next you need to create the real implementation of BookRepository that works off a File (or a Sql DB tommorrow if you want it). No one else has to know. Write integration tests for FileBasedBookRepository (that implements the above Role) and test that calling Load with a reference file gives the right objects and calling Save with a known list, persists them to the disk. i.e. uses real files These tests would be slow so mark them up with a tag or move it to a separate suite.
[TestFixture] [Category("Integration - Slow")] public class FileBasedBookRepository { [Test] public void CanLoadBooksFromFileOnDisk() {...} [Test] public void CanWriteBooksToFileOnDisk() {...} }
Finally there should be one/more acceptance tests that exercises Load and Save.
You could instead of passing a filename to your save function, pass a Stream, TextWriter or similar. Then when testing you can pass a memory-based implementation and verify the correct bytes are written without actually writing anything to disk.
To test problems and exceptions you could take a look at a mocking framework. This can help you to artifically generate a specific exception at the certain point in the save process and test that your code handles it appropriately.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With