Reputation: 2078
I have the below static class and a method in it which I need to unit test. I am able to But this method has the if condition which uses a Boolean private variable and if the value of it is false then it executes the steps in that if condition.
public static class Logger
{
private static bool bNoError = true;
public static void Log()
{
if (!bNoError)
{
//Then execute the logic here
}
else
{
//else condition logic here
}
}
}
Is there a way I can set the private field bNoError value to true so that I can have one test method which tests the logic in if condition.
Upvotes: 5
Views: 5391
Reputation: 10859
Sometimes, you can get so close to the code you're trying to test that you forget to think of the big picture and start focusing in too much on the implementation. Rather than thinking "When XXX happens, ...", you start thinking "When this variable is set, ...". When you get to this point, it's a sign that you might be focusing too much on the implementation and you're running a significant risk of creating very brittle tests that will break if you change anything about your implementation.
@Martin Noreke's post covered how to do what you're trying to. It feels to me though, like you may be testing the wrong thing. It seems like the next test you are going to write, is "Do XXX with Logger and test that bNoError
is set to false
"
Obviously it depends a bit on the rest of the Logger class, but it feels like perhaps an alternate approach might be:
Call Logger method XXX, shimming dependencies if necessary in order to trigger error state.
Call Logger.Log and validate expected behaviour
Assuming there is a way for bNoError
to get reset back to true
, you could then:
Call Logger method YYY, shimming dependencies if necessary to trigger error cleanup
Call Logger.Log and validate expected behaviour
Upvotes: 1
Reputation: 5314
Well, one way is to add a method to the original class and then shim it:
public static class Logger
{
// .... other stuff here
private static void SetbNoError(bool flag)
{
// leave implementation empty
}
}
Then in your test:
ShimLogger.SetbNoErrorBool = flag => bNoError = flag;
Upvotes: 0
Reputation: 25178
I don't recommend to use reflection on unit testing. It is difficult to maintain on large project with lot of developers, because it cannot be easily refactored, find.
Furthermore unit-test should test some behavior of class. If there is some kind of error handling in the tested class it should be accessible not only to unit-test but to the developer(invoker) in real scenario and not hidden by encapsulation. If I call some method in real scenario, I expect I can obtain error status or catch exception. Generally I prefer exception. Exception error handling can be tested easily by unit tested and no reflection to break encapsulation is needed.
So my suggestion is make it public:
public static class Logger
{
private bool bNoError = true;
public static void Log()
{
if (!bNoError)
{
//Then execute the logic here
}
else
{
//else condition logic here
}
}
public static bool IsAnyError()
{
return !bNoError;
}
}
Upvotes: 0
Reputation: 4146
For UnitTesting purposes, Microsoft has implemented a few helper classes (PrivateType and PrivateObject) that use reflection for scenarios like this.
PrivateType myTypeAccessor = new PrivateType(typeof(TypeToAccess));
myTypeAccessor.SetStaticFieldOrProperty("bNoError", false);
PrivateType is intended for static access, whereas PrivateObject is for testing against instantiated objects instead.
You will need to include the Microsoft.VisualStudio.TestTools.UnitTesting namespace from the Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll in order to use these.
Upvotes: 11
Reputation: 14687
You can use Reflection to do that for testing purpose. Though it's quite outlaw.
using System.Reflection;
................
................
var field = typeof(Logger).GetField("bNoError",
BindingFlags.Static |
BindingFlags.NonPublic);
// Normally the first argument to "SetValue" is the instance
// of the type but since we are mutating a static field we pass "null"
field.SetValue(null, false);
Upvotes: 6