Visual Studio allows unit testing of private methods via an automatically generated accessor class. I have written a test of a private method that compiles successfully, but it fails at runtime. A fairly minimal version of the code and the test is:
//in project MyProj
class TypeA
{
private List<TypeB> myList = new List<TypeB>();
private class TypeB
{
public TypeB()
{
}
}
public TypeA()
{
}
private void MyFunc()
{
//processing of myList that changes state of instance
}
}
//in project TestMyProj
public void MyFuncTest()
{
TypeA_Accessor target = new TypeA_Accessor();
//following line is the one that throws exception
target.myList.Add(new TypeA_Accessor.TypeB());
target.MyFunc();
//check changed state of target
}
The runtime error is:
Object of type System.Collections.Generic.List`1[MyProj.TypeA.TypeA_Accessor+TypeB]' cannot be converted to type 'System.Collections.Generic.List`1[MyProj.TypeA.TypeA+TypeB]'.
According to intellisense - and hence I guess the compiler - target is of type TypeA_Accessor. But at runtime it is of type TypeA, and hence the list add fails.
Is there any way I can stop this error? Or, perhaps more likely, what other advice do other people have (I predict maybe "don't test private methods" and "don't have unit tests manipulate the state of objects").
You can use the PrivateObject class:
Class target = new Class();
PrivateObject obj = new PrivateObject(target);
var retVal = obj.Invoke("PrivateMethod");
Assert.AreEqual(expectedVal, retVal);
Note: PrivateObject and PrivateType are not available for projects targeting netcoreapp2.0 - GitHub Issue 366
“There is nothing called as standard or best practice, probably they are just popular opinions”.
Same holds true for this discussion as well.
It all depends on what you think is a unit , if you think UNIT is a class then you will only hit the public method. If you think UNIT is lines of code hitting private methods will not make you feel guilty.
If you want to invoke private methods you can use "PrivateObject" class and call the invoke method. You can watch this indepth youtube video ( http://www.youtube.com/watch?v=Vq6Gcs9LrPQ ) which shows how to use "PrivateObject" and also discusses if testing of private methods are logical or not.
Another thought here is to extend testing to "internal" classes/methods, giving more of a white-box sense of this testing. You can use InternalsVisibleTo attribute on the assembly to expose these to separate unit testing modules.
In combination with sealed class you can approach such encapsulation that test method are visible only from unittest assembly your methods. Consider that protected method in sealed class is de facto private.
[assembly: InternalsVisibleTo("MyCode.UnitTests")]
namespace MyCode.MyWatch
{
#pragma warning disable CS0628 //invalid because of InternalsVisibleTo
public sealed class MyWatch
{
Func<DateTime> _getNow = delegate () { return DateTime.Now; };
//construktor for testing purposes where you "can change DateTime.Now"
internal protected MyWatch(Func<DateTime> getNow)
{
_getNow = getNow;
}
public MyWatch()
{
}
}
}
And unit test:
namespace MyCode.UnitTests
{
[TestMethod]
public void TestminuteChanged()
{
//watch for traviling in time
DateTime baseTime = DateTime.Now;
DateTime nowforTesting = baseTime;
Func<DateTime> _getNowForTesting = delegate () { return nowforTesting; };
MyWatch myWatch= new MyWatch(_getNowForTesting );
nowforTesting = baseTime.AddMinute(1); //skip minute
//TODO check myWatch
}
[TestMethod]
public void TestStabilityOnFebruary29()
{
Func<DateTime> _getNowForTesting = delegate () { return new DateTime(2024, 2, 29); };
MyWatch myWatch= new MyWatch(_getNowForTesting );
//component does not crash in overlap year
}
}
One way to test private methods is through reflection. This applies to NUnit and XUnit, too:
MyObject objUnderTest = new MyObject();
MethodInfo methodInfo = typeof(MyObject).GetMethod("SomePrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance);
object[] parameters = {"parameters here"};
methodInfo.Invoke(objUnderTest, parameters);
Ermh... Came along here with exactly the same problem: Test a simple, but pivotal private method. After reading this thread, it appears to be like "I want to drill this simple hole in this simple piece of metal, and I want to make sure the quality meets the specs", and then comes "Okay, this is not to easy. First of all, there is no proper tool to do so, but you could build a gravitational-wave observatory in your garden. Read my article at http://foobar.brigther-than-einstein.org/ First, of course, you have to attend some advanced quantum physics courses, then you need tons of ultra-cool nitrogenium, and then, of course, my book available at Amazon"...
In other words...
No, first things first.
Each and every method, may it private, internal, protected, public has to be testable. There has to be a way to implement such tests without such ado as was presented here.
Why? Exactly because of the architectural mentions done so far by some contributors. Perhaps a simple reiteration of software principles may clear up some missunderstandings.
In this case, the usual suspects are: OCP, SRP, and, as always, KIS.
But wait a minute. The idea of making everything publicly available is more of less political and a kind of an attitude. But. When it comes to code, even in then Open Source Community, this is no dogma. Instead, "hiding" something is good practice to make it easier to come familiar with a certain API. You would hide, for example, the very core calculations of your new-to-market digital thermometer building block--not to hide the maths behind the real measured curve to curious code readers, but to prevent your code from becoming dependent on some, perhaps suddenly important users who could not resist using your formerly private, internal, protected code to implement their own ideas.
What am I talking about?
private double TranslateMeasurementIntoLinear(double actualMeasurement);
It's easy to proclaim the Age of Aquarius or what is is been called nowadays, but if my piece of sensor gets from 1.0 to 2.0, the implementation of Translate... might change from a simple linear equation that is easily understandable and "re-usable" for everybody, to a pretty sophisticated calculation that uses analysis or whatever, and so I would break other's code. Why? Because they didn't understand the very priciples of software coding, not even KIS.
To make this fairy tale short: We need a simple way to test private methods--without ado.
First: Happy new year everyone!
Second: Rehearse your architect lessons.
Third: The "public" modifier is religion, not a solution.
Another option that has not been mentioned is just creating the unit test class as a child of the object that you are testing. NUnit Example:
[TestFixture]
public class UnitTests : ObjectWithPrivateMethods
{
[Test]
public void TestSomeProtectedMethod()
{
Assert.IsTrue(this.SomeProtectedMethod() == true, "Failed test, result false");
}
}
This would allow easy testing of private and protected (but not inherited private) methods, and it would allow you to keep all your tests separate from the real code so you aren't deploying test assemblies to production. Switching your private methods to protected methods would be acceptable in a lot of inherited objects, and it is a pretty simple change to make.
HOWEVER...
While this is an interesting approach to solving the problem of how to test hidden methods, I am unsure that I would advocate that this is the correct solution to the problem in all cases. It seems a little odd to be internally testing an object, and I suspect there might be some scenarios that this approach will blow up on you. (Immutable objects for example, might make some tests really hard).
While I mention this approach, I would suggest that this is more of a brainstormed suggestion than a legitimate solution. Take it with a grain of salt.
EDIT: I find it truly hilarious that people are voting this answer down, since I explicitly describe this as a bad idea. Does that mean that people are agreeing with me? I am so confused.....
From the book Working Effectively with Legacy Code:
"If we need to test a private method, we should make it public. If
making it public bothers us, in most cases, it means that our class is
doing too much and we ought to fix it."
The way to fix it, according to the author, is by creating a new class and adding the method as public.
The author explains further:
"Good design is testable, and design that isn't testable is bad."
So, within these limits, your only real option is to make the method public, either in the current or a new class.
I use this helper (object type extension)
public static TReturn CallPrivateMethod<TReturn>(
this object instance,
string methodName,
params object[] parameters)
{
Type type = instance.GetType();
BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Instance;
MethodInfo method = type.GetMethod(methodName, bindingAttr);
return (TReturn)method.Invoke(instance, parameters);
}
You can call it like this
Calculator systemUnderTest = new Calculator();
int result = systemUnderTest.CallPrivateMethod<int>("PrivateAdd",1,8);
One of the advantages is that it uses generics to pre-determine return type.
It's 2022 now!
...and we have .NET6
While this does not really answer the question, my preferred approach these days is to collocate code and test in the same C# project, with naming convention like <ClassName>.Tests.cs. Then I use internal access modifier instead of private.
In the project file, I have something like this:
<ItemGroup Condition="'$(Configuration)' == 'Release'">
<Compile Remove="**\*.Tests.cs" />
</ItemGroup>
to exclude the test files in release builds. Modify as needed.
FAQ 1: But sometimes you want to also test code in Release (optimized) build.
Answer: I find it unnecessary. I trust that the compiler will do its job without messing up my intent. So far, I've had no reason to question its ability to do so.
FAQ 2: But I really want to keep the method (or class) private.
Answer: Lots of excellent solutions in this page to try out. In my experience, having access modifier set to internal is usually more than enough since the method (or class) won't be visible outside the project it's defined. Beyond that, there's nothing more to hide.
Extract private method to another class, test on that class; read more about SRP principle (Single Responsibility Principle)
It seem that you need extract to the private method to another class; in this should be public. Instead of trying to test on the private method, you should test public method of this another class.
We has the following scenario:
Class A
+ outputFile: Stream
- _someLogic(arg1, arg2)
We need to test the logic of _someLogic; but it seem that Class A take more role than it need(violate the SRP principle); just refactor into two classes
Class A1
+ A1(logicHandler: A2) # take A2 for handle logic
+ outputFile: Stream
Class A2
+ someLogic(arg1, arg2)
In this way someLogic could be test on A2; in A1 just create some fake A2 then inject to constructor to test that A2 is called to the function named someLogic.
public static class PrivateMethodTester
{
public static object InvokePrivateMethodWithReturnType<T>(this T testObject, string methodName, Type[] methodParamTypes, object[] parameters)
{
//shows that we want the nonpublic, static, or instance methods.
var flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance;
//gets the method, but we need the methodparamtypes so that we don't accidentally get an ambiguous method with different params.
MethodInfo methodInfo = testObject.GetType().GetMethod(methodName, flags, null, methodParamTypes, null);
if (methodInfo == null)
{
throw new Exception("Unable to find method.");
}
//invokes our method on our object with the parameters.
var result = methodInfo.Invoke(testObject, parameters);
if (result is Task task)
{
//if it is a task, it won't resolve without forcing it to resolve, which means we won't get our exceptions.
task.GetAwaiter().GetResult();
}
return result;
}
}
Call it this way:
Type[] paramTypes = new Type[] { typeof(OrderTender), typeof(string) };
var parameters = new object[] { orderTender, OrderErrorReasonNames.FailedToCloneTransaction };
myClass.InvokePrivateMethodWithReturnType("myPrivateMethodName", paramTypes, parameters);
In VS 2005/2008 you can use private accessor to test private member,but this way was disappear in later version of VS
You can use nested classes to test private methods. For example (NUnit v3 is used):
internal static class A
{
// ... other code
private static Int32 Sum(Int32 a, Int32 b) => a + b;
[TestFixture]
private static class UnitTests
{
[Test]
public static void OnePlusTwoEqualsThree()
{
Assert.AreEqual(3, Sum(1, 2));
}
}
}
Furthermore tests related code can be moved to another file using 'partial class' feature, excluded from release builds using 'conditional compilation', etc. Advanced example:
File A.cs
internal static partial class A
{
// ... other code
private static Int32 Sum(Int32 a, Int32 b) => a + b;
}
File A.UnitTests.cs
#if UNIT_TESTING
partial class A
{
[TestFixture]
private static class UnitTests
{
[Test]
public static void OnePlusTwoEqualsThree()
{
Assert.AreEqual(3, Sum(1, 2));
}
}
}
#endif
I had another approach that it works for me. because I always run my tests in debug mode so I used #if DEBUG to add public before my private method. so my private method is like this:
public class Test
{
#if (DEBUG)
public
#endif
string PrivateMehtod()
{
return "PrivateMehtod called";
}
}
Sadly there is no PrivateObject class in .net6
However I wrote a small extension method capable of invoking private methods using reflection.
Have a look at the sample code:
class Test
{
private string GetStr(string x, int y) => $"Success! {x} {y}";
}
var test = new Test();
var res = test.Invoke<string>("GetStr", "testparam", 123);
Console.WriteLine(res); // "Success! testparam 123"
And here is the implementation of the extension method:
/// <summary>
/// Invokes a private/public method on an object. Useful for unit testing.
/// </summary>
/// <typeparam name="T">Specifies the method invocation result type.</typeparam>
/// <param name="obj">The object containing the method.</param>
/// <param name="methodName">Name of the method.</param>
/// <param name="parameters">Parameters to pass to the method.</param>
/// <returns>The result of the method invocation.</returns>
/// <exception cref="ArgumentException">When no such method exists on the object.</exception>
/// <exception cref="ArgumentException">When the method invocation resulted in an object of different type, as the type param T.</exception>
/// <example>
/// class Test
/// {
/// private string GetStr(string x, int y) => $"Success! {x} {y}";
/// }
///
/// var test = new Test();
/// var res = test.Invoke<string>("GetStr", "testparam", 123);
/// Console.WriteLine(res); // "Success! testparam 123"
/// </example>
public static T Invoke<T>(this object obj, string methodName, params object[] parameters)
{
var method = obj.GetType().GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
{
throw new ArgumentException($"No private method \"{methodName}\" found in class \"{obj.GetType().Name}\"");
}
var res = method.Invoke(obj, parameters);
if (res is T)
{
return (T)res;
}
throw new ArgumentException($"Bad type parameter. Type parameter is of type \"{typeof(T).Name}\", whereas method invocation result is of type \"{res.GetType().Name}\"");
}
If PrivateObject is not available and if the class under test is not a sealed class, you can make the methods and properties you want to expose protected. Create an inherited class in the unit test file with internal methods that expose the private methods/properties under test.
If the class under test is:
class MyClass{private string GetStr(string x, int y) => $"Success! {x} {y}";}
Change it to:
class MyClass{protected string GetStr(string x, int y) => $"Success! {x} {y}";}
In your unit test file create an inherited class something like this:
class MyClassExposed: MyClass
{
internal string ExposedGetStr(string x, int y)
{
return base.GetStr(x, y);
}
}
Now you can use the inherited class MyClassExposed to test the exposed methods and properties.
.NET doesn't allow use of Accessors anymore. You can use the code I posted here for an answer to a similar question.
How do you unit test private methods?
I have class Cache (wraps System.Runtime.Caching.MemoryCache) that I have created which has the following public methods:
bool Add(string key, object value)
bool Contains(string key)
How do I test the Contains() method without using the Add() method in the first place to add an item to the Cache??? Surely if I use the Add() method within the unit test for the Contains() method this would be wrong?
How do I test the Contains() method without using the Add() method in the first place to add an item to the Cache?
Assert that it returns false.
Surely if I use the Add() method within the unit test for the Contains() method this would be wrong?
Of course not. You're testing a unit which has a Contains() that differs in behaviour after you've called Add(). Not having tests for Contains() called after Add() would be wrong.
I think I understand your dilemma. You are asking if you use a new method to test another new method. Sort of testing an unknown with an unknown.
To me I would look at it as test isolation case of assumption. Let me explain...
The following applies if both methods are there and you are responsible for testing them.
In the first instance, you want to test the Add(,) method. In that case, I would 'assume' that all other methods work correctly. So in that case, I would run an Add(key,value) and check that it Asserts true, and then verify with a call to Contains(key) and ensure that it Asserts true. Even though Contains() is untested.
Then in the second instance, you assume that Add(,) is working properly and test the Contains() method. I always test based on the assumption that I've got blinkers on and testing something specific, a specific method, a specific class and run on the assumption that everything supporting required to run the test actually works.
In reality, this is not always the case and some of the supporting methods don't work as expected. But, the test will let you know. And that's what it's there for. To help reveal those issues.
You probably already have this test in mind but, here's a quick example where you can combine the testing of these two methods into a single test. Of course, you can split it into two tests (one thats Add() centric and one that's Contains() centric) but they will look fairly similar. I hope it helps.
public class SomeClass : MemoryCache
{
public SomeClass() : base("Test")
{
}
public bool Add(string key, object value)
{
return Add(key, value, DateTime.Now.AddDays(1));
}
}
[TestFixture]
public class TestSomeClass
{
[Test]
public void TestSomeClassMethod1()
{
var instance = new SomeClass();
const string key = "someKey";
Assert.IsFalse(instance.Contains(key));
Assert.IsTrue(instance.Add(key, new object()));
Assert.IsTrue(instance.Contains(key));
instance.Remove(key);
Assert.IsFalse(instance.Contains(key));
}
}
But in a pure TDD approach, you would do this:
Create the Add(,) method then write the following test:
[Test]
public void TestAdd()
{
var instance = new SomeClass();
const string key = "someKey";
Assert.IsTrue(instance.Add(key, new object()));
}
Then you would create the Contains() method and then write the following test:
[Test]
public void TestContains()
{
var instance = new SomeClass();
const string key = "someKey";
Assert.IsFalse(instance.Contains(key));
// A purest will say that you don't need the following Assert
// for the Add as it is not what you are testing.
// But I don't see any harm
Assert.IsTrue(instance.Add(key, new object()));
Assert.IsTrue(instance.Contains(key));
instance.Remove(key);
Assert.IsFalse(instance.Contains(key));
}
I have to write a unit test for some methods and I reached a method that returns void:
public virtual void ReadCities(string filename)
{
var engine = new FileHelperEngine(typeof (GeoDbCity));
_geoDbCities = engine.ReadFile(filename) as GeoDbCity[];
}
And my test method is:
[Test]
public void CheckIfCitiesWereRead()
{
var getGeoDbCitiesMock = new Moq.Mock<GeoDbReader>();
getGeoDbCitiesMock.Setup(y => y.ReadCities("ConstCities.csv"));
Assert.NotNull(getGeoDbCitiesMock.Object.ReadCities("ConstCities.csv"));
}
When assert is being called i'm getting an error:
Argument type 'void' is not assignable to parameter type 'object'.
My question is:
How to deal with void type methods and how test them? In this particular case how to test if ReadCities method actualy read something?
If a method does not return anything, then that method must have some side-effect such as changing a property of the class. Test that side-effect, e.g. test the value of said property.
You question actually consists of two questions: how to test void() methods, and how to test this ReadCities(string fileName) method.
In response to the first - In case your void method changes the internal state of the object, then that is what you can test for:
Example:
public class Person
{
public int age;
public void SetAge(int age)
{
this.age = age;
}
}
Then your test would be
var p = new Person();
p.SetAge(12);
Assert.AreEqual(p.age, 12);
In response to the question how to test that ReadCities method, well, you don't want to Mock it for one. You only mock the stuff you don't want to test - in a test.
Add a CSV file to your testproject ( type = content, action = copy always ) and use the DeploymentItem attribute to copy the CSV file into the test folder.
Then test with
var service = new Service();
service.ReadCities(pathToCsvFile);
Assert.NotNull(service.Cities);
// Actually - you want better assertions
So maybe ReadCities might be a void method, you can test the internal state of the object after, so the cities list.
If you don't expose the list of cities, there's another thing called the InternalsVisibleToAttribute which allows your tests to access private members. However, then we can get into a discussion of whether private members need to be tested in the first place.
In the strictest sense, if you ware testing only the ReadCities method, your mock shouldn't be testing that engine.ReadFile actually did something (you would have another unit test for that). You should isolate this method by mocking the call to engine.ReadFile (which I think you've done, but I'm not completely familiar with Moq).
In any case, what you'll likely need to do is create a public accessor for _geoDbCities that you can check in your Assert.
To be succint:
class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute() : base(new Fixture().Customize(new AutoMoqCustomization()))
{
}
}
public interface IWeapon { bool LaunchAtEarth(double probabilityOfHitting); }
public class DeathStar
{
readonly IWeapon _weapon;
public DeathStar(IWeapon weapon) // guard clause omitted for brevity
{
this._weapon = weapon;
}
public bool FireFromOrbit(double probabilityOfHitting)
{
return this._weapon.LaunchAtEarth(probabilityOfHitting);
}
}
// Make me pass, pretty please with a cherry on the top
[Test, AutoMoqData]
[TestCase(0.1), TestCase(0.5), TestCase(1)]
public void AutoMoqData_should_fill_rest_of_arguments_that_are_not_filled_by_TestCase(
double probabilityOfHitting,
[Frozen] Mock<IWeapon> weapon,
DeathStar platform)
{
Assert.That(weapon, Is.Not.Null);
Assert.That(platform, Is.Not.Null);
} // Ignored with error: Wrong number of parameters specified.
// Make me pass, too!
[Test, AutoMoqData]
[TestCaseSource("GetTestCases")]
public void AutoMoqData_should_fill_rest_method_arguments_that_are_not_filled_by_TestCaseSource(
double probabilityOfHitting,
[Frozen] Mock<IWeapon> weapon,
DeathStar platform)
{
Assert.That(weapon, Is.Not.Null);
Assert.That(platform, Is.Not.Null);
} // Ignored with error: Wrong number of parameters specified.
IEnumerable<TestCaseData> GetTestCases()
{
yield return new TestCaseData(0.1);
yield return new TestCaseData(0.5);
yield return new TestCaseData(1);
}
This seems to do the trick if I were using Xunit:
http://nikosbaxevanis.com/blog/2011/08/25/combining-data-theories-in-autofixture-dot-xunit-extension/
I cannot find anything equivalent for NUnit.
This: http://gertjvr.wordpress.com/2013/08/29/my-first-open-source-contribution/
seems to be already working in the current version of AutoFixture.NUnit2 (the AutoData attribute), but it doesn't handle the case when I want to make it take a params object[] such that the first parameters in the test method are filled using the attribute arguments and the rest are passed through to the AutoData attribute.
Can someone guide me towards the right direction ? There seems to be something missing I cannot grasp.
OP's code here doesn't worked for me in nunit2.6.3. In fact it doesn't even compile, not sure if the nunit infrastructure has changed. It turns out that I've missed the nunit.core.dll reference, after adding it, it compiled. But I used my own implementation.
So I've rolled my own implementation. Implementation goes like this: We'll ask the AutoFixture for the parameters, it will give all the parameters which Test method needs, then we'll just over write the parameter values which we need.
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class InlineAutoDataAttribute : AutoDataAttribute
{
private readonly object[] values;
public InlineAutoDataAttribute(params object[] values)
: base(new Fixture().Customize(new AutoMoqCustomization()))
{
this.values = values;
}
public override IEnumerable<object[]> GetData(MethodInfo method)
{
var testCaseData = base.GetData(method);
foreach (object[] caseValues in testCaseData)
{
if (values.Length > caseValues.Length)
{
throw new InvalidOperationException("Number of parameters provided is more than expected parameter count");
}
Array.Copy(values, caseValues, values.Length);
yield return caseValues;
}
}
}
How to use:
[Test]
[InlineAutoData(1, 2)]
[InlineAutoData(3, 4)]
public void Whatever_Test_Name(int param1, int param2, TemplateOrder sut)
{
//Your test here
Assert.That(sut, Is.Not.Null);
}
Test will be invoked with
param1 = 1, param2 = 2, sut = given by auto fixture
param1 = 3, param2 = 4, sut = given by auto fixture
You could argue that this implementation isn't efficient, but at least that works as expected. I've contacted Mark Seemann(Creator of AutoFixture) also, but it seems he also couldn't help with this. So for now I can live with this.
I've got it working.
Unfortunately, due to some bad design choices in NUnit's extensibility API in 2.6 (no way to override or remove any of the built-in test case providers), I was forced to resort to some reflection to get at the internal ExtensionCollection instance in the "TestCaseProviders" class.
TL;DR: This should work in NUnit 2.6.x only. NUnit 3.0 is NOT compatible.
How to use
Just add the supplied [AutoMoqData] on a test already using the regular [TestCase] and [TestCaseSource] attributes. Test case parameters will be filled first and the rest of the test method arguments will be handled via AutoFixture. You may change the AutoMoqDataAttribute to use any different fixture customization (example: AutoRhinoMockCustomization) as you wish.
How to get it working with ReSharper's test runner
If you add this to an external assembly and reference it in your test project, NUnit won't see your add-in (because it only looks in the immediate test assembly being loaded or in DLLs in an "addins" subfolder of the currently running test runner executable.
In such case, just make an empty class in the current test project and make it inherit from
AutoMoqDataAddIn. Tested using ReSharper unit test runner and it sees the test cases properly and auto-generates the test case names using only the "real" test parameters.
Show me the code!
GitHub: https://gist.github.com/rwasef1830/ab6353b43bfb6549b396