我想测试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'
中受到保护
@Test
fun `checks init`() {
val b = B()
b.init()
// assert work done
}
为什么它不起作用?这怎么可以解决(我想避免公开方法)?
答案 0 :(得分:5)
由于Kotlin通过不允许包访问来降低protected
(与Java相比)的可见性,我可以找到的最佳选择是使用反射进行解决(因为这是用于测试我没有理由不这样做)< / p>
private fun invokeHiddenMethod(name: String) {
val method = sut.javaClass.getDeclaredMethod(name)
method.isAccessible = true
method.invoke(testSubject)
}
答案 1 :(得分:4)
protected
与Kotlin中的不一样。
在Java中,同一个包中的所有内容都可以访问protected
方法。
见In Java, difference between default, public, protected, and private
在Kotlin中,protected
表示您只能在同一个类或其任何子类中访问它。见Visibility Modifiers - Kotlin
唯一可行的方法是使用internal
修饰符,并使该方法对同一模块中的测试可见。
答案 2 :(得分:-1)
@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)
}
-------------------------------------------- -----------------------------------
我写了一个样本供您参考
kotlin是用Java开发的。
Java示例类
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;
}
}
Java测试样本
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)
}
}