【Java单元测试】实习项目实际问题4--监听器处理函数

问题简单描述

针对单例模式的测试类的add,remove,clear函数进行单元测试,是对监听器列表的操作

具体情况

  1. 被测试类Java代码
public class FordAmbientLightManager extends FordCommonManager {

    private static final String TAG = "FordAmbientLightManager";
    private static FordAmbientLightManager manager;
    private AmbientLightSettingRsp ambientLightSettingRsp;
    private List<IAmbientLightChange> mIAmbientLightChangeListeners;
    
    //单例模式,接口
    public static synchronized FordAmbientLightManager getInstance(Context context) {
        if (null == manager) {
            manager = new FordAmbientLightManager(context);
        }
        return manager;
    }

    //初始化函数
    public FordAmbientLightManager(Context context) {
        super(context, APPID_ID_1021);
        mIAmbientLightChangeListeners = new ArrayList<>();
        addIResponseCallbackListener(mCallback);
        addISynchronizationInterfaceListener(mISynchronizationInterface);
    }
    //监听器接口
    public interface IAmbientLightChange {
        void onAmbientLightChange(int type, int value);
    }

    //添加监听器
    public void addIAmbientLightChangeListeners(IAmbientLightChange listener) {
        if (mIAmbientLightChangeListeners != null) {
            mIAmbientLightChangeListeners.add(listener);
        }
    }

    //移除监听器
    public void removeIAmbientLightChangeListeners(IAmbientLightChange listener) {
        if (mIAmbientLightChangeListeners != null) {
            mIAmbientLightChangeListeners.remove(listener);
        }
    }

    //清空监听器
    public void clearIAmbientLightChangeListeners() {
        if (mIAmbientLightChangeListeners != null) {
            mIAmbientLightChangeListeners.clear();
        }
    }
    }
  1. 问题具体分析
    mIAmbientLightChangeListeners是私有的一个IAmbientLightChange列表,对add,remove,clear函数测试的主要难点是如何断言,并且每一个函数都有两个条件需要判断,需要分成两种情况分别进行测试
  2. 具体测试代码
//test类初始化部分
class FordAmbientLightManagerUT extends BaseUnitTest {


    private FordAmbientLightManager fordAmbientLightManager;
    private Context context;
    private AutoCloseable closeable;

    @BeforeAll
    public static void beforeAll() {
        mockStatic(Log.class);
        mockStatic(Car.class);
    }

    @BeforeEach
    public void beforeEach() {
        closeable = MockitoAnnotations.openMocks(this);
        Context context = Mockito.mock(Context.class);
        Mockito.when(context.getApplicationContext()).thenReturn(context);
        fordAmbientLightManager = FordAmbientLightManager.getInstance(context);
    }

    @AfterEach
    public void afterEach() throws IllegalAccessException, NoSuchFieldException {
        try {
            closeable.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        Class c = fordAmbientLightManager.getClass();
        Field manager = c.getDeclaredField("manager");
        manager.setAccessible(true);
        manager.set(fordAmbientLightManager, null);

    }

//具体测试部分
    //监听器列表为空:验证函数调用不抛异常
    @Test
    public void testAddIAmbientLightChangeListeners_mIAmbientLightChangeListenersIsNull() throws NoSuchFieldException, IllegalAccessException {
        //prepare
        //使用反射设置私有变量值
        Field mIAmbientLightChangeListeners = getField(fordAmbientLightManager, "mIAmbientLightChangeListeners");
        setField(mIAmbientLightChangeListeners, fordAmbientLightManager, null);

        //assert
        assertDoesNotThrow(() -> {
          fordAmbientLightManager.addIAmbientLightChangeListeners(Mockito.mock(FordAmbientLightManager.IAmbientLightChange.class));
        });
    }

    //添加监听器且监听器列表不为空
    @Test
    public void testAddIAmbientLightChangeListeners_mIAmbientLightChangeListenersIsNotNull() throws NoSuchFieldException, IllegalAccessException {
        //PREPARE

        //创建一个列表(已经是非空),利用反射设置私有变量值
        FordAmbientLightManager.IAmbientLightChange mockListeners =Mockito.mock(FordAmbientLightManager.IAmbientLightChange.class);
        List<FordAmbientLightManager.IAmbientLightChange> test_list = new ArrayList<>();
        Field mIAmbientLightChangeListeners_Listeners = getField(fordAmbientLightManager, "mIAmbientLightChangeListeners");
        setField(mIAmbientLightChangeListeners_Listeners, fordAmbientLightManager, test_list);

        //INVOKE
        fordAmbientLightManager.addIAmbientLightChangeListeners(mockListeners);
        //VERIFY
        Field mIAmbientLightChangeListeners_test = getField(fordAmbientLightManager, "mIAmbientLightChangeListeners");
        List<FordAmbientLightManager.IAmbientLightChange> test = (List<FordAmbientLightManager.IAmbientLightChange>) mIAmbientLightChangeListeners_test.get(fordAmbientLightManager);
        //验证生成的列表中含有我们想添加的监听器
        assertTrue(test.contains(mockListeners));
    }

    //监听器列表为空:验证函数调用不抛异常
    @Test
    public void testRemoveIAmbientLightChangeListeners_mIAmbientLightChangeListenersIsNull() throws NoSuchFieldException, IllegalAccessException {
        //prepare
        Field mIAmbientLightChangeListeners = getField(fordAmbientLightManager, "mIAmbientLightChangeListeners");
        setField(mIAmbientLightChangeListeners, fordAmbientLightManager, null);
        //assert
        assertDoesNotThrow(() -> {
            fordAmbientLightManager.removeIAmbientLightChangeListeners(Mockito.mock(FordAmbientLightManager.IAmbientLightChange.class));
        });
    }

    @Test
    public void testRemoveIAmbientLightChangeListeners_mIAmbientLightChangeListenersIsNotNull() throws NoSuchFieldException, IllegalAccessException {
        //PREPARE
        FordAmbientLightManager.IAmbientLightChange mockListeners = Mockito.mock(FordAmbientLightManager.IAmbientLightChange.class);
        List<FordAmbientLightManager.IAmbientLightChange> test_list = new ArrayList<>();
        Field mIAmbientLightChangeListeners_Listeners = getField(fordAmbientLightManager, "mIAmbientLightChangeListeners");
        test_list.add(mockListeners);
        setField(mIAmbientLightChangeListeners_Listeners, fordAmbientLightManager, test_list);

        //INVOKE
        fordAmbientLightManager.removeIAmbientLightChangeListeners(mockListeners);
        //VERIFY
        Field mIAmbientLightChangeListeners_test = getField(fordAmbientLightManager, "mIAmbientLightChangeListeners");
        List<FordAmbientLightManager.IAmbientLightChange> test = (List<FordAmbientLightManager.IAmbientLightChange>) mIAmbientLightChangeListeners_test.get(fordAmbientLightManager);
        //验证不含想移除的监听器
        assertFalse(test.contains(mockListeners));
    }

    
    //监听器列表为空:验证函数调用不抛异常
    @Test
    public void testClearIAmbientLightChangeListeners_mIAmbientLightChangeListenersIsNull() throws NoSuchFieldException, IllegalAccessException {
        //prepare
        Field mIAmbientLightChangeListeners = getField(fordAmbientLightManager, "mIAmbientLightChangeListeners");
        setField(mIAmbientLightChangeListeners, fordAmbientLightManager, null);
        //assert
        assertDoesNotThrow(() -> {
            fordAmbientLightManager.clearIAmbientLightChangeListeners();
        });
    }

    @Test
    public void testClearIAmbientLightChangeListeners_mIAmbientLightChangeListenersIsNotNull() throws NoSuchFieldException, IllegalAccessException {
        //PREPARE

        FordAmbientLightManager.IAmbientLightChange mockListeners = Mockito.mock(FordAmbientLightManager.IAmbientLightChange.class);
        List<FordAmbientLightManager.IAmbientLightChange> test_list = new ArrayList<>();
        Field mIAmbientLightChangeListeners_Listeners = getField(fordAmbientLightManager, "mIAmbientLightChangeListeners");
        test_list.add(mockListeners);
        setField(mIAmbientLightChangeListeners_Listeners, fordAmbientLightManager, test_list);
        //INVOKE
        fordAmbientLightManager.clearIAmbientLightChangeListeners();
        //VERIFY
        Field mIAmbientLightChangeListeners_test = getField(fordAmbientLightManager, "mIAmbientLightChangeListeners");
        List<FordAmbientLightManager.IAmbientLightChange> test = (List<FordAmbientLightManager.IAmbientLightChange>) mIAmbientLightChangeListeners_test.get(fordAmbientLightManager);
        //验证列表全部清空
        assertTrue(test.isEmpty());
    }

    //获取类的私有属性
    public Field getField(Object test_target, String targetFieldName) throws NoSuchFieldException {
        Class c = test_target.getClass();
        Field field = c.getDeclaredField(targetFieldName);
        field.setAccessible(true);
        return field;
    }
    //更改私有变量的值
    public void setField(Field field, Object obj, Object value) throws IllegalAccessException {
        field.setAccessible(true);
        field.set(obj, value);
    }
   }

存在问题

  1. 使用了大量反射

技术细节

  1. 新建我们想要的列表,用反射代替被测试类的私有变量列表,
  2. 利用断言判断不同行为的结果,断言通过就代表测试通过

小结

  1. 一开始写add时为了让列表非空写出了这样的代码
    @Test
    public void testAddIAmbientLightChangeListeners_mIAmbientLightChangeListenersIsNotNull() throws NoSuchFieldException, IllegalAccessException {
        //PREPARE

        FordAmbientLightManager.IAmbientLightChange mockListeners = Mockito.mock(FordAmbientLightManager.IAmbientLightChange.class);
        List<FordAmbientLightManager.IAmbientLightChange> test_list = new ArrayList<>();
        Field mIAmbientLightChangeListeners_Listeners = getField(fordAmbientLightManager, "mIAmbientLightChangeListeners");
        test_list.add(mockListeners);
        setField(mIAmbientLightChangeListeners_Listeners, fordAmbientLightManager, test_list);

        //INVOKE
        fordAmbientLightManager.addIAmbientLightChangeListeners(mockListeners);
        //VERIFY
        Field mIAmbientLightChangeListeners_test = getField(fordAmbientLightManager, "mIAmbientLightChangeListeners");
        List<FordAmbientLightManager.IAmbientLightChange> test = (List<FordAmbientLightManager.IAmbientLightChange>) mIAmbientLightChangeListeners_test.get(fordAmbientLightManager);
        assertTrue(test.contains(mockListeners));


    }

很搞笑的错误,其实new一个list得到的list就是非空的,虽然是空列表但是非空,不是null,因为代码写的少所以这个点一直没发现,,,
2.也有比较简单的单元测试方式(看的小组其他成员,写的比我简单)

    public void addISuixintingDisplayStateListenerListeners(ISuixintingDisplayStateListener listener) {
        if (mISuixintingDisplayStateListeners != null) {
            mISuixintingDisplayStateListeners.add(listener);
        }
    }
    //此处只展示非空情况
    @Test
    public void testAddIWlcmFrwlAnimationStateListeners_mIWlcmFrwlAnimationStateListenersNotNull() throws NoSuchFieldException, IllegalAccessException {
        Field field = FordCarVendorExtensionManager.class.getDeclaredField("mIWlcmFrwlAnimationStateListeners");
        List<FordCarVendorExtensionManager.IWlcmFrwlAnimationState> mIWlcmFrwlAnimationStateListeners = Mockito.mock(List.class);
        FordCarVendorExtensionManager.IWlcmFrwlAnimationState listener = Mockito.mock(FordCarVendorExtensionManager.IWlcmFrwlAnimationState.class);
        field.setAccessible(true);
        field.set(target, mIWlcmFrwlAnimationStateListeners);
        target.addIWlcmFrwlAnimationStateListeners(listener);
        //直接验证mock后的list是否调用了add函数
        Mockito.verify(mIWlcmFrwlAnimationStateListeners).add(listener);
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值