0


【杂谈】Unchecked cast: ‘java.lang.Object‘ to ‘T‘ 与单元测试

文章目录

一些杂乱的小问题记录

1. Unchecked cast: ‘java.lang.Object’ to ‘T’

问题描述
有时,我们要自定义一些工具类、工具方法或数据结构,此时需要用到泛型。

我们指导泛型既可以指定类型,也可以作为通配符使用。有时,当我们使用通配符进行类型转换时,IDE会报:

Unchecked cast: 'java.lang.Object' to 'T' 

翻译过来就是:未选中强制转换:‘java.lang.Object’到’T’ 。
这只是个IDE的警告,一般情况下并不影响程序运行,但如果放到实际工作中,这个代码总是报黄,总是不舒服,也容易让人产生代码不规范的感觉。
i1

参考文章
知乎优秀参考文章

解决方案

  • 忽略:添加@SuppressWarnings(“unchecked”)注解。如果直接在单个方法添加这个注解,代表每次只是忽略。根据参考文章的说法,这种单次忽略治标不治本。如果我们可以确定要返回的类型,如List等,则可参考参考文章的做法。
@Override@SuppressWarnings("unchecked")publicTget(int i){if(i <INIT_LENGTH|| i > length-1){thrownewArrayIndexOutOfBoundsException();}return(T)getElements()[i];}
  • 使用泛型方法进行类型转换:参考文章提供了List/Map的类型转换。本文借助 Class.cast() 方法进行稍微安全一些的转换,但由于泛型的缘故,工具类依然需要添加上面的忽略注解
@SuppressWarnings("unchecked")publicstatic<T>TtypeConversion(Object o,Class<?> tClass){return(T) tClass.cast(o);}
@OverridepublicTget(int i){if(i <INIT_LENGTH|| i > length-1){thrownewArrayIndexOutOfBoundsException();}returnGenericTypeChangeUtil.typeConversion(getElements()[i],getElements()[i].getClass());}

2. 单元测试

问题描述
既然在上一小节我们做了一个类型转换方法,该方法又是个人在学习数据结构过程中,自己写的一个顺序表。那么总得测试一下这个顺序表是否可用。

本例我们就用 Mockito + Junit 进行单元测试吧

参考教程
bilibili-Mockito优秀教程

测试
顺序表源码:

importjava.util.Arrays;importjava.util.List;importjava.util.Objects;/**
 * 顺序表的实现
 * @author Sharry
 * @since 2023/9/16
 */publicclassSequenceTable<T>implementsISequenceTable<T>{/**
     * init length : 0
     */publicfinalintINIT_LENGTH=0;/**
     * hash code constant
     */publicfinalintHASH_TIMES=31;/**
     * array to store sequence data
     */privateObject[] elements;/**
     * this sequence table's length
     */privateint length;publicSequenceTable(T[] elements){this.elements = elements;this.length = elements.length;}publicSequenceTable(int length){this.elements =newObject[length];this.length = length;}publicSequenceTable(){this.elements =newObject[INIT_LENGTH];this.length =INIT_LENGTH;}publicSequenceTable(T[] elements,int length){if(length < elements.length){thrownewArrayIndexOutOfBoundsException();}this.elements = elements;this.length = length;}publicObject[]getElements(){return elements;}publicvoidsetElements(Object[] elements){this.elements = elements;}publicintgetLength(){return length;}publicvoidsetLength(int length){this.length = length;}@Overridepublicbooleanequals(Object o){if(this== o){returntrue;}if(!(o instanceofSequenceTable)){returnfalse;}SequenceTable<?> that =(SequenceTable<?>) o;returngetLength()== that.getLength()&&Arrays.equals(getElements(), that.getElements());}@OverridepublicinthashCode(){int result =Objects.hash(getLength());
        result =HASH_TIMES* result +Arrays.hashCode(getElements());return result;}@OverridepublicStringtoString(){return"SequenceTable{"+"elements="+Arrays.toString(elements)+", length="+ length +'}';}@OverridepublicbooleanisEmpty(){if(elements.length ==0){returnthis.getLength()==INIT_LENGTH||this.getElements()==null;}for(Object element : elements){if(null!= element){returnfalse;}}returntrue;}@Overridepublicintsize(){returngetLength();}@OverridepublicTget(int i){if(i <INIT_LENGTH|| i > length-1){thrownewArrayIndexOutOfBoundsException();}returnGenericTypeChangeUtil.typeConversion(getElements()[i],getElements()[i].getClass());}@Overridepublicbooleanset(int i,T x){if(isOutOfBounds(i)){thrownewArrayIndexOutOfBoundsException();}Object[] eArr =getElements();Object e =getElements()[i];if( e ==null||!e.equals(x)){
            eArr[i]= x;setElements(eArr);returntrue;}returnfalse;}@Overridepublicintinsert(int i,T x){if(isOutOfBounds(i)){thrownewArrayIndexOutOfBoundsException();}if(set(i,x)){return i;}return-1;}@Overridepublicintinsert(T x){if(set(length-1,x)){return length-1;}return-1;}@OverridepublicTremove(int i){if(isOutOfBounds(i)){thrownewArrayIndexOutOfBoundsException();}Object e =getElements()[i];Object[] eArr =getElements();
        eArr[i]=null;setElements(eArr);returnGenericTypeChangeUtil.typeConversion(e,e.getClass());}@Overridepublicintsearch(T key){Object[] eArr =getElements();for(int i =0; i < eArr.length ; i++){boolean ifNull = eArr[i]!=null&& eArr[i]== key;if(ifNull ||Objects.equals(eArr[i], key)){return i;}}return-1;}@Overridepublicbooleancontains(T key){returnsearch(key)!=-1;}@OverridepublicintinsertDifferent(T x){if(contains(x)){return-1;}insert(x);return length-1;}@OverridepublicTremove(T key){T element;if(!contains(key)){returnnull;}else{
            element =GenericTypeChangeUtil.typeConversion(getElements()[search(key)],getElements()[search(key)].getClass());set(search(key),null);}returnGenericTypeChangeUtil.typeConversion(element,element.getClass());}@Override@SuppressWarnings("unchecked")publicbooleanaddAll(List<T> list){if(list ==null|| list.size()==0){returnfalse;}Object[] source =getElements();Object[] tar =newObject[this.getLength()+ list.size()];int tarLength = tar.length;if(this.length >=0){System.arraycopy(source,0, tar,0,this.length);}for(int i =this.length-1; i < tarLength; i++){
            tar[i]= list.get(tarLength-i);}SequenceTable<T> ns =newSequenceTable<T>((T[])tar,tarLength);setElements(ns.getElements());setLength(ns.length);returntrue;}privatebooleanisOutOfBounds(int i){return i <INIT_LENGTH|| i > length -1;}}

工具类源码:

/**
 * Generic type change util
 *
 * @author Sharry
 * @since 2023/9/21
 */publicclassGenericTypeChangeUtil{@SuppressWarnings("unchecked")publicstatic<T>TtypeConversion(Object o,Class<?> tClass){return(T) tClass.cast(o);}}

分别对顺序表、工具类进行Mocktio + Junit 5进行测试:

依赖:

<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.8.2</version><scope>test</scope></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-inline</artifactId><version>4.3.1</version><scope>test</scope></dependency>

顺序表测试:

@TestvoidgetElements(){Mockito.when(sequenceTable.getElements()).thenCallRealMethod();
        log.info("Forward value:{}",Arrays.toString(sequenceTable.getElements()));Object[] elements = sequenceTable.getElements();Assertions.assertEquals(elements,sequenceTable.getElements());}// 其余测试代码略.....

工具类测试:

@TestvoidtypeConversion(){try(MockedStatic<GenericTypeChangeUtilTest> testUtil =Mockito.mockStatic(GenericTypeChangeUtilTest.class)){Assertions.assertEquals(1,(Integer)GenericTypeChangeUtil.typeConversion(1,Integer.class));}}

由于日常工作时测试是个大佬,因此我们普通马仔在日常开发中若是交期紧,就会在开发完后Swagger文档稍微测试一下就给测试了,没有顾及太多单元测试,上面的测试也只是照着参考教程写的。趁此机会就补补单元测试的概念吧:

为什么要Mockito + Junit

  • Junit : 最常见的Java单元测试工具之一。一般情况下,Junit已集成在一些工具或框架中。如IDEA就自带了Junit,可以用IDEA的Generate生成对应测试类。
  • Mockito:使用Mock对象的方式进行测试。使用Mock可以让我们在相对独立的测试环境,使用专用的对象进行模拟,可以进一步规范对象的动作,捕捉对象的行为。简单来说就是更独立,不用去动实际要动的对象。

常见概念

  • 断言:assert。assert具体在代码的体现就是Junit提供的方法了,其作用为:当断言里的结果是我们预期的结果时,测试通过;否则IDE会报红。具体assert的用法会根据Junit的版本不同而有差异,使用示例在上面的代码中。
  • 测试类常用注解:
    • @BeforeEach : 准备工作。在上述例子中的体现就是对Mock进行初始化。
    • @AfterEach : 结束工作。
  • Mokito常用注解与方法
    • @Spy : 使用真实的对象(有些对象难以Mock)
    • @Mock : 模拟对象
    • MockitoAnnotations.openMocks(class) 配合初始化注解使用,建议放在@BefoeEach方法上
    • Mockito.when().thenCallRealMethod() 方法,使用执行该方法的返回值,而不是自己定义的thenReturn值
    • Mokito.when().thenThrow()方法 ,抛出异常
    • @InjectMocks :将@Mock的对象注入到该注解修饰的对象中
标签: java 单元测试 log4j

本文转载自: https://blog.csdn.net/CoderSharry/article/details/133141330
版权归原作者 CoderSharry 所有, 如有侵权,请联系我们删除。

“【杂谈】Unchecked cast: ‘java.lang.Object‘ to ‘T‘ 与单元测试”的评论:

还没有评论