I'm struggling with the unit testing of a method that has been tested thru integration testing. The thing, is that this method explicitly calls a sealed
class, hence making it unmockable via Moq.
public async Task<DatabaseSymbol> ConnectAndReturnDatabaseSchema(
string environment,
string cluster
)
{
KustoConnectionStringBuilder connection = null;
if (environment == "LOCAL")
{
connection = new KustoConnectionStringBuilder(
cluster,
"AXA"
).WithAadAzCliAuthentication(false);
}
else
{
//TODO: Manage other environments
}
...
}
KustoConnectionStringBuilder
is a sealed class, with no interfacing, and only a single parent class. I know solutions like JustMock or TypeMock provide solutions, but I'm not paying for a testing library. What's the best way to proceed using Moq (or another free testing library?)
CodePudding user response:
Unit tests should test the interface of the method or class, not the implementation. So it should not matter if the method uses a sealed class, it can just be tested as part of the method.
While your test might test more than a single method, that is fine in my opinion. A "Unit" should be some grouping of functionality that provides some type of service. Focusing to much on classes and methods are not very useful in my opinion. After all, your method also uses string
, do you feel the need to mock this as well? Where would you draw the limit?
It is also possible that the design is poor, and the sealed class should be separated out, and the dependency replaced by an interface.
Things become a bit more cumbersome when considering modules that deal with IO or databases. One approach is to setup a test database so you can actually do tests all the way to the database layer. Another approach is to mock away the database, but this will mean that the classes that are replaced by the mocks will not be tested. That is usually not a large problem since these classes can be made very thin and low risk. But each approach have some advantages and disadvantages, it is impossible to tell what is more useful for you.
My main point is to write tests that are useful in some way. Not just because people on the internet say every method should have a unit test.
CodePudding user response:
... an extra level of indirection solves every problem ...
OR
... increasing the level of abstraction one can make the problem easier to understand/resolve ...
OR
... general principle for managing complexity through abstraction ...
etc.
If you are facing a problem like above you can introduce a thin wrapper with an interface. This pattern is usually referred as an Anti Corruption Layer whenever you are dealing with different domain contexts or 3rd party libraries.
public interface IKustoConnectionStringBuilder
{
IKustoConnectionStringBuilder WithAadAzCliAuthentication(string cluster, string otherParameter, bool xyz);
}
public class KustoConnectionStringBuilderWrapper: IKustoConnectionStringBuilder
{
public IKustoConnectionStringBuilder WithAadAzCliAuthentication(string cluster, string otherParameter, bool xyz)
=> new KustoConnectionStringBuilder(cluster, otherParameter)
.WithAadAzCliAuthentication(false);
}
If your ConnectAndReturnDatabaseSchema
method would rely on IKustoConnectionStringBuilder
abstraction rather than concrete implementation (KustoConnectionStringBuilderWrapper
) then you are ready for unit testing.