我正在为我的java应用程序编写集成测试框架,我遇到了一个我无法解决的问题。请让我解释一下:
以下代码段是简化的类,以提高可见性:
我得到了以下抽象类:
public class SomeTest {
TestModelFactory testModelFactory;
@Before
public void init(){
testModelFactory = new TestModelFactory();
}
@Test
public void someTest(){
AbstractTestModel anyModel = testModelFactory.createModel("someIdOfTheServer");
//ERROR: this does not work! Cannot resolve method doSomethingElse():
anyModel.doSomething().as(ConcreteTestModel1.class).doSomethingElse();
//as() method returns AbstractTestModel instead of ConcreteTestModel1
//this works:
AbstractTestModel as = anyModel.as(ConcreteTestModel1.class);
//this does not work:
ConcreteTestModel1 asConcreteTestModel1 = anyModel.as(ConcreteTestModel1.class);
}
}
可能有这样的具体课程:
public abstract class AbstractTestModel {
/*
Not possible to return the superclass anymore
public T doSomething(){
return getThis();
}
public T getThis(){
return (T) this;
}
*/
public <U extends AbstractTestModel> U as(Class<U> type){
AbstractTestModel obj = this;
if (obj.getClass().isAssignableFrom(type)){
return type.cast(obj);
}else{
throw new AssertionError("This (" + obj.getClass().getName() +")could not be resolved to the expected class " + type.getName());
}
}
}
我还写了一个Factory类。此工厂从服务器下载JSON对象并实例化其中一个concret类 - 具体取决于JSON响应。这个具体的类有许多帮助方法来测试JSON响应。问题是,工厂方法总是返回“AbstractTestModel”。
集成测试看起来像这样(简化):
{{1}}
作为(类类型)的方法应该检查给定的类是否有效,将“this”强制转换为所需的类并返回它,但它总是返回AbstractTestModel。
如果我将“as”方法设为静态,或者如果我摆脱这样的泛型类......
{{1}}
...然后它工作正常,但当然我不能再用所有其他方法返回具体类了。
感谢您阅读这篇长篇文章。 你知道我在这里做错了什么吗?有解决方案吗?
感谢您的任何小费,祝您有愉快的一天!
曼努埃尔
答案 0 :(得分:1)
问题是编译器需要在编译时推断出类型。此代码主要是提供的,但为了演示,我在doSomethingElse
添加了一些输出,并添加ConcreteTestModelX
扩展ConcreteTestModel1
( 注意 < / strong> 我从T
方法中移除了as
类型,以探索在进一步的探索性测试中与通用类型进行交互的方式。
public abstract class AbstractTestModel<T extends AbstractTestModel> {
public T doSomething() {
return getThis();
}
public T getThis() {
return (T) this;
}
public <U extends AbstractTestModel> U as(Class<U> type) {
if (getClass().isAssignableFrom(type)) {
return type.cast(this);
} else {
throw new AssertionError("This (" + getClass().getName()
+ ") could not be resolved to the expected class " + type.getName());
}
}
}
class ConcreteTestModel1 extends AbstractTestModel<ConcreteTestModel1> {
public void doSomethingElse() {
System.out.println("This is \"" + getClass().getSimpleName() + "\" doing something else");
}
}
class ConcreteTestModelX extends ConcreteTestModel1 {
}
并通过此测试
import org.junit.Test;
public class SomeTest {
@Test
public void someTest(){
AbstractTestModel<ConcreteTestModel1> anyModel = new ConcreteTestModel1();
ConcreteTestModel1 asConcreteTestModel1 = anyModel.as(ConcreteTestModel1.class);
asConcreteTestModel1.doSomethingElse();
AbstractTestModel anyModelX = new ConcreteTestModelX();
ConcreteTestModel1 asConcreteTestModelX = (ConcreteTestModel1)anyModelX;
asConcreteTestModelX.doSomethingElse();
}
}
似乎你在测试中遇到的问题是你用于模型的变量是没有泛型的,然后编译器剥离泛型看到这个答案https://stackoverflow.com/a/18277337/7421645
基于此,我创建了一些新的测试来探索:
import org.junit.Test;
public class SomeTest {
@Test
public void concreteTest(){
ConcreteTestModel1 asConcreteTestModel1 = getConcreteModel(new ConcreteTestModel1(), ConcreteTestModel1.class);
asConcreteTestModel1.doSomethingElse();
}
@Test
public void concreteExtendsTest(){
ConcreteTestModel1 asConcreteTestModelX = getConcreteModel(new ConcreteTestModelX(), ConcreteTestModelX.class);
asConcreteTestModelX.doSomethingElse();
}
private <T extends ConcreteTestModel1> T getConcreteModel(T anyModel, Class<T> classType) {
return anyModel.as(classType);
}
@Test
public void vanillaCastingTest(){
AbstractTestModel anyModelX = new ConcreteTestModelX();
ConcreteTestModel1 asConcreteTestModelX = (ConcreteTestModel1)anyModelX;
asConcreteTestModelX.doSomethingElse();
}
@Test
public void abstractGenericTest(){
AbstractTestModel<ConcreteTestModel1> anyModel = new ConcreteTestModel1();
ConcreteTestModel1 asConcreteTestModel1 = anyModel.as(ConcreteTestModel1.class);
asConcreteTestModel1.doSomethingElse();
}
@Test
public void failedGenericTest(){
AbstractTestModel anyModel = new ConcreteTestModel1();
ConcreteTestModel1 asConcreteTestModel1 = getAs(anyModel);
asConcreteTestModel1.doSomethingElse();
}
private ConcreteTestModel1 getAs(AbstractTestModel<ConcreteTestModel1> anyModel) {
return anyModel.as(ConcreteTestModel1.class);
}
}
答案 1 :(得分:0)
感谢所有答案,我终于找到了问题。实际上很容易:
工厂需要返回&#34; AbstractTestModel&lt;❓&gt;&#34;而不只是&#34; AbstractTestModel&#34;。我添加了&lt;❓&gt;返回AbstractTestModel的每个方法。现在它工作得很好:)谢谢大家。没有你就无法找到答案。