Scenario 2: PreconditionTest – Architectural Principles
This scenario explores that any precondition implemented in a supertype should yield the same outcome in its subtypes, but subtypes can be less strict about it, never more.The following code is the consumer of the subject under test:
var value = 5;
var result = sut.IsValid(value);
Console.WriteLine($”Do something with {result}”);
The preceding code is very standard. We have the value variable that could come from anywhere. Then we pass it to the IsValid method. Finally, we do something with the result; in this case, we write a line to the console.The initial subject under test (the SuperClass) simulates that a precondition exists that enforces that the value must be positive. Here’s the code:
public class SuperClass
{
public virtual bool IsValid(int value)
{
if (value < 0)
{
throw new ArgumentException(
“Value must be positive.”,
nameof(value)
);
}
return true;
}
}
Next, the SubClassOk class simulates that the execution changed and tolerates negative values up to -10. Everything is fine when executing the code because the precondition is less strict. Here’s the code:
public class SubClassOk : SuperClass
{
public override bool IsValid(int value)
{
if (value < -10)
{
throw new ArgumentException(
“Value must be greater or equal to -10.”,
nameof(value)
);
}
return true;
}
}
Finally, the SubClassBreak class simulates that the execution changed and restricts using values under 10. When executing the code, it breaks because we were not expecting that error; the precondition was more strict than the SuperClass. Here’s the code:
public class SubClassBreak : SuperClass
{
public override bool IsValid(int value)
{
if (value < 10) // Break LSP
{
throw new ArgumentException(
“Value must be greater than 10.”,
nameof(value)
);
}
return true;
}
}
Yet another example of how a simple change can break its consumers and the LSP. Of course, this is an overly simplified example focusing only on the precondition, but the same applies to more complex scenarios. Coding is like playing with blocks.