Suppose we have a Calculator
with a divide method throwing error if the denominator is 0:
public class Calculator
{
public double Divide(int x, int y)
{
if (y == 0)
{
throw new ArgumentOutOfRangeException(paramName: nameof(y), message: CalculatorErrorMessages.DenominatorShouldNotBeZero);
}
return (double)x / y;
}
}
public static class CalculatorErrorMessages
{
public static string DenominatorShouldNotBeZero = "Denominator should not be zero.";
}
And here's the unit test which tries to test the raise of the exception:
public class CalculatorUnitTest
{
[Fact]
public void Test1()
{
var calculator = new Calculator();
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => calculator.Divide(1, 0));
Assert.Contains(CalculatorErrorMessages.DenominatorShouldNotBeZero, ex.Message);
}
}
Stryker.NET reports the exception message survives mutation:
But that mutation survival is not an actual problem, since both the unit test code and the app code generate the exception message in the same way. I don't want to duplicate and maintain error messages in the app and the unit test.
For this, I could make Stryker ignore mutations on CalculatorErrorMessages
but it does not sound like a good idea. Stryker will not catch a situation where the unit test does not handle error messages like it should. For example, let's say I add a new method DivideV2
in the Calculator which also throws an exception, and in the unit-test, instead of using the actual error message constant, I hard-code the expected error message:
[Fact]
public void Test2()
{
var calculator = new Calculator();
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => calculator.DivideV2(1, 0));
Assert.Contains("Denominator should not be zero.", ex.Message);
}
In this situation, the mutation survival should really not be ignored.
How can I make in such a way Stryker:
- Does not show me 'false' mutations survivals
- Still make my code unit tested by mutations
- Not duplicate the error message strings across the app and unit-test
So, long story short, one way to achieve your goals is to make the string
const
. Keep in mind that this way you are making use of the Stryker limitation described here. So different mutation testing framework or maybe some future Stryker version can still mark this as a surviving mutant.Also, keep in mind that
const
is not "better" thanstatic
and replacing one with another can have unpleasant consequences. You shouldn't make itconst
just to calm Stryker down. In your case, I'd probably have itstatic readonly
.Ultimately, you need to define the level of testing for yourself, how black/white box you want it to be, how tautological you want it to be. And remember, you can ignore specific mutations.