我正在构建一个类库,它将有一些公共和私有方法。我希望能够对私有方法进行单元测试(主要是在开发过程中,但也可以用于将来的重构)。
正确的做法是什么?
我正在构建一个类库,它将有一些公共和私有方法。我希望能够对私有方法进行单元测试(主要是在开发过程中,但也可以用于将来的重构)。
正确的做法是什么?
当前回答
1)如果你有一个遗留代码,那么测试私有方法的唯一方法就是反射。
2)如果它是新代码,那么你有以下选项:
使用反射(使之复杂) 在同一个类中编写单元测试(使生产代码变得丑陋 其中还包含测试代码) 在某种util类中重构并使方法为公共 使用@VisibleForTesting注释并删除private
I prefer the annotation method, simplest and least complicated. The only issue is that we have increased the visibility which I think is not a big concern. We should always be coding to interface, so if we have an interface MyService and an implementation MyServiceImpl then we can have the corresponding test classes that is MyServiceTest (test interface methods) and MyServiceImplTest (test private methods). All clients should anyway be using the interface so in a way even though the visibility of the private method has been increased it should not really matter.
其他回答
I don't agree with the "you should only be interested in testing the external interface" philosophy. It's a bit like saying that a car repair shop should only have tests to see if the wheels turn. Yes, ultimately I'm interested in the external behavior but I like my own, private, internal tests to be a bit more specific and to the point. Yes, if I refactor, I may have to change some of the tests, but unless it's a massive refactor, I'll only have to change a few and the fact that the other (unchanged) internal tests still work is a great indicator that the refactoring has been successful.
You can try to cover all internal cases using only the public interface and theoretically it's possible to test every internal method (or at least every one that matters) entirely by using the public interface but you may have to end up standing on your head to achieve this and the connection between the test cases being run through the public interface and the internal portion of the solution they're designed to test may be difficult or impossible to discern. Having pointed, individual tests that guarantee that the internal machinery is working properly is well worth the minor test changes that come about with refactoring - at least that's been my experience. If you have to make huge changes to your tests for every refactoring, then maybe this doesn't make sense, but in that case, maybe you ought to rethink your design entirely. A good design should be flexible enough to allow for most changes without massive redesigns.
对于任何想要运行私有方法的人来说。这适用于任何单元测试框架,只使用旧的Reflection。
public class ReflectionTools
{
// If the class is non-static
public static Object InvokePrivate(Object objectUnderTest, string method, params object[] args)
{
Type t = objectUnderTest.GetType();
return t.InvokeMember(method,
BindingFlags.InvokeMethod |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Static,
null,
objectUnderTest,
args);
}
// if the class is static
public static Object InvokePrivate(Type typeOfObjectUnderTest, string method, params object[] args)
{
MemberInfo[] members = typeOfObjectUnderTest.GetMembers(BindingFlags.NonPublic | BindingFlags.Static);
foreach(var member in members)
{
if (member.Name == method)
{
return typeOfObjectUnderTest.InvokeMember(method, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, typeOfObjectUnderTest, args);
}
}
return null;
}
}
然后在你的实际测试中,你可以这样做:
Assert.AreEqual(
ReflectionTools.InvokePrivate(
typeof(StaticClassOfMethod),
"PrivateMethod"),
"Expected Result");
Assert.AreEqual(
ReflectionTools.InvokePrivate(
new ClassOfMethod(),
"PrivateMethod"),
"Expected Result");
还请注意,internalsvisibletoattribute有一个要求,您的程序集必须是强命名的,如果您在一个以前没有这个要求的解决方案中工作,这就会产生它自己的一组问题。我使用访问器来测试私有方法。请看这个问题的例子。
JAVA语言
在这里,您可以使用模拟行为覆盖测试类的特定方法。
对于下面的代码:
public class ClassToTest
{
public void methodToTest()
{
Integer integerInstance = new Integer(0);
boolean returnValue= methodToMock(integerInstance);
if(returnValue)
{
System.out.println("methodToMock returned true");
}
else
{
System.out.println("methodToMock returned true");
}
System.out.println();
}
private boolean methodToMock(int value)
{
return true;
}
}
测试类将是:
public class ClassToTestTest{
@Test
public void testMethodToTest(){
new Mockup<ClassToTest>(){
@Mock
private boolean methodToMock(int value){
return true;
}
};
....
}
}
测试私有方法可能没有用处。然而,我有时也喜欢从测试方法调用私有方法。大多数时候为了防止代码重复用于测试数据生成…
微软为此提供了两种机制:
访问器
转到类定义的源代码 右键单击类名 选择“创建私有访问器” 选择要在其中创建访问器的项目 你将得到一个名为foo_accessor的新类。 该类将在编译期间动态生成,并提供所有公共成员。
然而,当涉及到原始类的接口更改时,该机制有时有点棘手。所以,大多数时候我避免使用这个。
PrivateObject类 另一种方法是使用microsoft。visualstudio。testtools。unittest。privateobject
// Wrap an already existing instance
PrivateObject accessor = new PrivateObject( objectInstanceToBeWrapped );
// Retrieve a private field
MyReturnType accessiblePrivateField = (MyReturnType) accessor.GetField( "privateFieldName" );
// Call a private method
accessor.Invoke( "PrivateMethodName", new Object[] {/* ... */} );