I have lots of code like the following. An "Entity" type that has some numerical properties. To be able to reuse the arithmetic I write the arithmetic functions against an interface. I use extension methods, which are easy to use. I use similar extension methods to convert the numerical values into formatted text to display. And then finally I have a type that stores the display text for the UI to use. (A "row".)
public class Entity : IEntity {
public int NumberOfAs { get; set; }
public int NumberOfBs { get; set; }
}
public interface IEntity {
int NumberOfAs { get; }
int NumberOfBs { get; }
}
public static class EntityFormula {
public static int GetTotalNumber(this IEntity me) =>
me.NumberOfAs + me.NumberOfBs;
}
public static class EntityFormatter {
public static string GetTotalNumberText(this IEntity me) =>
me.GetTotalNumber().ToString("#,##0");
}
public sealed class EntityRow {
public string TotalNumberText { get; }
public EntityRow(
Entity e
) {
TotalNumberText = e.GetTotalNumberText();
}
}
This allows my UI to reuse the arithmetic for display purposes.
The trouble I'm having is in testing. It's easy to test GetTotalNumber()
, but I notice that when I test GetTotalNumberText()
and EntityRow
that I am re-testing the arithmetic again.
Recently I started to learn to use Moq to generate mocks. What I would like to do is mock IEntity
and/or Entity
so that the call to GetTotalNumber()
is not re-tested in GetTotalNumberText()
, and the same for GetTotalNumberText()
in the EntityRow
class.
However, since these are extension methods, they are not "stubbed" when IEntity
is mocked. They are essentially static methods and you can't mock static methods.
There are some options here, but I'm not sure the best approach.
One option, I think, is to convert the static extension method classes into concrete classes and then extract interfaces from them:
public sealed class EntityFormula : IEntityFormula {
readonly IEntity mEntity;
public EntityFormula(IEntity entity) => mEntity = entity;
public int GetTotalNumber() => mEntity.NumberOfAs + mEntity.NumberOfBs;
}
public interface IEntityFormula {
int GetTotalNumber();
}
This allows me to inject/mock the formula and formatter classes so that I can stub the method calls and not retest them. But it's a little less convenient to use and it creates a bunch of interfaces that wouldn't need to exist otherwise, so I'm not sure I want to commit to doing that to my entire project.
Another option is to just retest the logic and forget about isolating this code. That's what I was going to do but when I learned about isolation I really started liking the idea that I was testing the code in this method only and not re-testing the code in that other method that I've already tested.
Is one of these the correct choice or are there maybe other options I'm not thinking of (such as maybe organizing this code differently in the first place)?
EntityFormula
andEntityFormatter
in separate namespaces and only reference theEntityFormatter
namespace in your test, the other one being replaced with a stubbedEntityFormula.GetTotalNumber()
of your own?