Search code examples
javaandroidmockitorobolectricpowermockito

Mockito test check if bluetooth is enabled


I'm trying to learn Mockito and TDD.

I have presenter with methods:

  @Override
    public void startScanning() {
        if (isLocationPermissionGranted() && isBluetoothEnabled()) {
            mPresenterView.onStartScanBtnClick();
        } else if (!isBluetoothEnabled()) {
            mPresenterView.displayDialogRequestingBluetooth();
        } else if (!isLocationPermissionGranted()) {
            mPresenterView.displayDialogRequestingPermission();
        }
    }

    @Override
    public boolean isLocationPermissionGranted() {
        return false;
    }

    @Override
    public boolean isBluetoothEnabled() {
        return false;
    }

Question is how I can test 2 methods on the bottom using Mockito Roboelectric or w/e.

 @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        mScanningPresenter = new ScanningPresenter(mView);

        mockBluetoothAdapter = PowerMockito.mock(BluetoothAdapter.class);
    }



  @Test
    public void shouldPassPowerMock() {

        assertEquals(true, mockBluetoothAdapter != null);
    }

    @Test
    public void shouldDisplayBluetoothRequestWhenDisabled() {

        mScanningPresenter.startScanning();

        PowerMockito.when(!mockBluetoothAdapter.isEnabled()).thenReturn(false);

        verify(mView).displayDialogRequestingBluetooth();
    }

I added PowerMock and created test to be sure it's working ^^ and I'm adding test which showing what I want TO DO but don't know how yet

My idea is to make this interface methods as protected method in presenter and create MockingClass. Or Create seperate interface helper and mock it.

I have open mind for any clean solutions / propositions.


Solution

  • Whenever I see someone start to use Powermockito for a new project I immediately think of Padme's words to Anakin in Episode 3:

    padme vs anakin

    You're going down a path I can't follow

    There's no need for Powermockito here - just good old Java and Mockito :-)

    You have some public methods in your Presenter which should probably be extracted to separate classes. The best kinds of presenters simply delegate their actions to other classes and manipulate the view using show methods. That is the single responsibility of the presenter. You could easily do something like this:

    class PermissionsChecker {
    
       private final Context context;
    
       PermissionsChecker(Context context) {
           this.context = context;
       }
    
        public boolean isLocationPermissionGranted() {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
                return false;
            if (context.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED)
                return false;
            return true;
       }
    }
    

    Then:

    class BluetoothAdapterWrapper {
    
        private final BluetoothAdapter bluetoothAdapter;
    
        BluetoothAdapterWrapper(BluetoothAdapater adapter) { 
            this.bluetoothAdapter = adatper;
        }
    
        public boolean isBluetoothEnabled() {
            return bluetoothAdapter.isEnabled();
        }
    }
    

    Now your presenter looks something like this:

    class ScanningPresenter {
    
        private final ScanningView scanningView;
        private final PermissionsChecker permissionsChecker;
        private final BluetoothAdapterWrapper bluetoothAdapterWrapper;
    
        ScanningPresenter(ScanningView scanningView, PermissionsChecker permissionsChecker, BluetoothAdapterWrapper bluetoothAdapterWrapper) {  
            this.scanningView = scanningView;
            this.permissionsChecker = permissionsChecker;
            this.bluetoothAdapterWrapper = bluetoothAdapterWrapper;
        }
    
        @Override
        public void startScanning() {
            if (isLocationPermissionGranted() && isBluetoothEnabled()) {
                scanningView.onStartScanBtnClick();
            } else if (!isBluetoothEnabled()) {
                scanningView.displayDialogRequestingBluetooth();
            } else if (!isLocationPermissionGranted()) {
                scanningView.displayDialogRequestingPermission();
            }
        }
    
        @Override
        public boolean isLocationPermissionGranted() {
            return permissionsChecker.isLocationPermissionGranted();
        }
    
        @Override
        public boolean isBluetoothEnabled() {
            return bluetoothAdapterWrapper.isEnabled();
        }
    }
    

    You notice now we don't even need those public methods on the presenter - you can remove them from the presenter's contract and make them private or completely get rid of them if you want.

    Now your test looks something like this:

    @Mock PermissionsChecker mockPermissionsChecker;
    @Mock BluetoothAdapterWrapper mockBluetoothAdapterWrapper;
    @Mock ScanningView mockScanningView;
    
    //system under test
    ScanningPresenter scanningPresenter;
    
    @Before
    public void setUp() {
        MockitoAnnotations.init(this);
        scanningPresenter = new ScanningPresenter(mockScanningView, mockPermissionsChecker, mockBluetoothAdapterWrapper);
    }
    
    @Test
    public void shouldDisplayBluetoothRequestWhenDisabled() {
        //arrange
        when(mockBluetoothAdapter.isEnabled()).thenReturn(false);
    
        //act
        mScanningPresenter.startScanning();
    
        //assert
        verify(mockScanningView).displayDialogRequestingBluetooth();
    }