The rules are:
- It must be a unit test (so don't touch the file system).
- The public signature for
CodeUnderTest
must not be changed.can be extended not reduced - You're allowed to use DI/your favorite mocking framework.
- You can only add code where you see /**/.
[Test]
public void Test()
{
/**/
var text = CodeUnderTest.GetUpperText("foo.txt" /**/);
Assert.That(text, Is.EqualTo("BAR"));
/**/
}
public class CodeUnderTest
{
/**/
public static string GetUpperText(string path /**/)
{
var text = File.ReadAllText(path);
return text.ToUpperInvariant();
}
/**/
}
Please comment below or tweet me @jcansdale.
A good functional implementation of this challenge is trivial, so here we suffer from the simplicity of the original problem statement. While you can call
File.ReadAllText
from an F# function, it's by definition impure. The property of impurity is transitive, so becauseFile.ReadAllText
is impure, any function calling it would also be impure.In functional programming, we really, really like our functions to be pure, so we'd refactor any impure indirect input to direct input. Since the output type of
File.ReadAllText
isstring
, this can be refactored into a function that takes a string as input:This is where the simplicity of the example begins to show, because the
getUpperText
function doesn't seem to add much value... Again, we should consider it a stand-in for more complex logic.Since this function is pure, it's easy to unit test:
In a production system, then, you can compose it with any source of
string
values, including the contents of files:That example composes a function that takes a
string
(a file path) as input, and returns astring
.For a more complex demonstration of such separation of pure and impure functions, see e.g. this article: http://blog.ploeh.dk/2016/03/18/functional-architecture-is-ports-and-adapters