Unit testing Kotlin中的测试无法访问受保护的方法

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”中受保护 为什么不起作用?这是如何

我想测试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)
}
}