Unit testing Kotlin中的测试无法访问受保护的方法
我想测试B类:Unit testing Kotlin中的测试无法访问受保护的方法,unit-testing,kotlin,Unit Testing,Kotlin,我想测试B类: class B : A { override fun init() { // do work here } } class A { protected fun init() { } // will be called by internal logic } 在Java中,在测试方法中调用:b.init()(测试类与测试主题在同一个包中,但在Kotlin编译器中,它抱怨: 无法访问“init”:它在“B”中受保护 为什么不起作用?这是如何
class B : A {
override fun init() {
// do work here
}
}
class A {
protected fun init() { } // will be called by internal logic
}
在Java中,在测试方法中调用:b.init()
(测试类与测试主题在同一个包中,但在Kotlin编译器中,它抱怨:
无法访问“init”:它在“B”中受保护
为什么不起作用?这是如何解决的(我希望避免将方法公开)?
在Java中受保护
与在Kotlin中不同
在Java中,同一个包中的所有内容都可以访问受保护的方法。
看
在Kotlin中,protected
意味着您只能在同一类或其任何子类中访问它。看
唯一可能的方法是使用
内部
修饰符,并使方法对同一模块中的测试可见。由于Kotlin通过不允许包访问来降低受保护(与Java相比)上的可见性,所以我能找到的最佳选择是解决反射问题(因为这是为了测试,我看没有理由不这样做)
Java测试样本
----------------------------------------------------------------
Kotlin版本
Kotlin示例类
科特林样品试验
导入junit.framework.Assert.assertEquals
导入org.junit.Test
导入java.lang.reflect.InvocationTargetException
班级学生测验{
@试验
乐趣测试(){
//测试私有属性:id
val student=StudentKt(“Leon”,80,60)
val预期值=“A01234567”
var-actual=“”
val field=student.javaClass.getDeclaredField(“id”)
field.isAccessible=true
实际值=字段。获取(学生)作为字符串
资产质量(预期、实际)
}
@试验
有趣的名字测试(){
//测试公共属性:名称
val student=StudentKt(“Leon”,80,60)
val=“Leon”
val实际值=student.name
资产质量(预期、实际)
}
@试验
有趣的测试(){
//测试专用方法:isPass()--无参数
val student=StudentKt(“Leon”,80,60)
预期值=真
实际值=假
//如果方法中没有参数,则不需要设置类型
val方法=student.javaClass.getDeclaredMethod(“isPass”)
method.isAccessible=true
//如果方法中没有参数,则不需要设置类型
实际值=方法。调用(学生)为布尔值
资产质量(预期、实际)
}
@试验
有趣的getTotalTest(){
//测试私有方法:getTotal()
val student=StudentKt(“Leon”,80,60)
预期值=80+60
实际值=0
//带出参数的类型
val方法=student.javaClass.getDeclaredMethod(
“getTotalScore”,Int::class.java,Int::class.java
)
method.isAccessible=true
//设置参数
val参数=阵列Fnulls(2)
参数[0]=80
参数[1]=60
实际=方法。调用(学生,*参数)为Int
资产质量(预期、实际)
}
@试验
fun getAvgTest(){
//测试公共方法:getAvg()
val student=学生(“Leon”,80,60)
预期值=(80+60)/2.0
val实际值=student.avg
//(双预期、双实际、双ε)
资产质量(预期、实际、0.0)
}
}
可能重复@JBNizet在重写方法上更改可见性是不可能的,而使用internal
和public
则是不可接受的-特别是因为我可以在JavaClass中这样做,Class A实际上是库的一部分,所以不能更改,而且当我试图将internal
放在重写方法上时,它是不允许的结婚
@Test
fun `checks init`() {
val b = B()
b.init()
// assert work done
}
private fun invokeHiddenMethod(name: String) {
val method = sut.javaClass.getDeclaredMethod(name)
method.isAccessible = true
method.invoke(testSubject)
}
@Test
fun getTotalTest() {
//test private method: getTotal(int, int)
//sample class
val student = StudentKt("Leon", 80, 60)
//set your expected value
val expected = 80 + 60
var actual = 0
// bring the type of the parameters
//getDeclaredMethod("method name", parameter type, ...)
//if there is no parameter = getDeclaredMethod("method name")
val method = student.javaClass.getDeclaredMethod(
"getTotalScore", Int::class.java, Int::class.java
)
//set it could be Accessible
method.isAccessible = true
//set your parameters
val parameters = arrayOfNulls<Any>(2)
parameters[0] = 80
parameters[1] = 60
//force the result as Int(the output type of your method)
actual = method.invoke(student, *parameters) as Int
//or you could just put the parameters in the method
//actual = method.invoke(student, 80, 60) as Int
//check your result
assertEquals(expected, actual)
}
public class Student {
//properties
private String id = "A01234567";
public String name = "Leon";
private int englishScore = 0;
private int mathScore = 0;
//constructor
public Student(String name, int englishScore, int mathScore) {
this.name = name;
this.englishScore = englishScore;
this.mathScore = mathScore;
}
//private method
private boolean isPass() {
return (englishScore>=60 && mathScore>=60);
}
//private method
private int getTotalScore(int english, int math) {
return english+math;
}
//public method
public double getAvg() {
return (englishScore+mathScore) / 2.0;
}
}
import org.junit.Assert;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static org.junit.Assert.assertEquals;
public class StudentTest {
@Test
public void idTest() {
//test private property: id
Student student = new Student("Leon", 80, 60);
String expected = "A01234567";
String actual = "";
Field field = student.getClass().getDeclaredField("id");
field.setAccessible(true);
actual = (String) field.get(student);
assertEquals(expected, actual);
}
@Test
public void nameTest() {
//test public property: name
Student student = new Student("Leon", 80, 60);
String expected = "Leon";
String actual = student.name;
assertEquals(expected, actual);
}
@Test
public void isPassTest() {
//test private method: isPass() -- no parameter
Student student = new Student("Leon", 80, 60);
boolean expected = true;
boolean actual = false;
Method method = student.getClass().getDeclaredMethod("isPass");
method.setAccessible(true);
actual = (boolean) method.invoke(student);
assertEquals(expected, actual);
}
@Test
public void getTotalTest() {
//test private method: getTotal()
Student student = new Student("Leon", 80, 60);
int expected = 80+60;
int actual = 0;
// bring the type of the parameters
Method method = student.getClass().getDeclaredMethod("getTotalScore", int.class, int.class);
method.setAccessible(true);
//set parameters
Object[] parameters = new Object[2];
parameters[0] = 80;
parameters[1] = 60;
actual = (int) method.invoke(student, parameters);
assertEquals(expected, actual);
}
@Test
public void getAvgTest() {
//test public method: getAvg()
Student student = new Student("Leon", 80, 60);
double expected = (80+60)/2.0;
double actual = student.getAvg();
//(double expected, double actual, double epsilon)
assertEquals(expected, actual ,0);
}
}
class StudentKt(name:String, englishScore:Int, mathScore:Int) {
//properties
private var id:String = "A01234567"
var name:String = "Leon"
private var englishScore:Int = 0
var mathScore:Int = 0
//initialization
init {
this.name = name
this.englishScore = englishScore
this.mathScore = mathScore
}
//private method
private fun isPass():Boolean {
return (englishScore>=60 && mathScore>=60)
}
//private method
private fun getTotalScore(english: Int, math: Int): Int {
return english + math
}
//public method
fun getAvg():Double {
return (englishScore + mathScore) / 2.0
}
}
import junit.framework.Assert.assertEquals
import org.junit.Test
import java.lang.reflect.InvocationTargetException
class StudentKtTest {
@Test
fun idTest() {
//test private property: id
val student = StudentKt("Leon", 80, 60)
val expected = "A01234567"
var actual = ""
val field = student.javaClass.getDeclaredField("id")
field.isAccessible = true
actual = field.get(student) as String
assertEquals(expected, actual)
}
@Test
fun nameTest() {
//test public property: name
val student = StudentKt("Leon", 80, 60)
val expected = "Leon"
val actual = student.name
assertEquals(expected, actual)
}
@Test
fun isPassTest() {
//test private method: isPass() -- no parameter
val student = StudentKt("Leon", 80, 60)
val expected = true
var actual = false
//you don't need set type if there is no parameter in the method
val method = student.javaClass.getDeclaredMethod("isPass")
method.isAccessible = true
//you don't need set type if there is no parameter in the method
actual = method.invoke(student) as Boolean
assertEquals(expected, actual)
}
@Test
fun getTotalTest() {
//test private method: getTotal()
val student = StudentKt("Leon", 80, 60)
val expected = 80 + 60
var actual = 0
// bring the type of the parameters
val method = student.javaClass.getDeclaredMethod(
"getTotalScore", Int::class.java, Int::class.java
)
method.isAccessible = true
//set parameters
val parameters = arrayOfNulls<Any>(2)
parameters[0] = 80
parameters[1] = 60
actual = method.invoke(student, *parameters) as Int
assertEquals(expected, actual)
}
@Test
fun getAvgTest() {
//test public method: getAvg()
val student = Student("Leon", 80, 60)
val expected = (80 + 60) / 2.0
val actual = student.avg
//(double expected, double actual, double epsilon)
assertEquals(expected, actual, 0.0)
}
}