AltBeacon / android-beacon-library

Allows Android apps to interact with BLE beacons
Apache License 2.0
2.84k stars 836 forks source link

Test Robolectric failed #399

Open kmenager opened 8 years ago

kmenager commented 8 years ago

I have implemented your library with background support as described in your sample. In my Application class, I get an instance of BeaconManager, I create a RegionBootstrap and set background scan period.

I try to implement test in my app using Roboelectric.

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
public class SampleTest {

    @Test
    public void shouldPass() {

    }
}

I've got the following error :

org.altbeacon.beacon.BeaconManager$ServiceNotDeclaredException: The BeaconService is not properly declared in AndroidManifest.xml.

I follow the response from @davidgyoung http://stackoverflow.com/questions/30499138/servicenotdeclaredexception-the-beaconservice-is-not-properly-declared-in-andro and add the line before BeaconManager.getInstance()

BeaconManager.setsManifestCheckingDisabled(true);

Know I have another error from RegionBootstrap

java.lang.NullPointerException
    at android.os.Message.sendToTarget(Message.java:416)
    at org.robolectric.shadows.ShadowMessenger.send(ShadowMessenger.java:24)
    at android.os.Messenger.send(Messenger.java)
    at org.altbeacon.beacon.BeaconManager.startMonitoringBeaconsInRegion(BeaconManager.java:534)
    at org.altbeacon.beacon.startup.RegionBootstrap$InternalBeaconConsumer.onBeaconServiceConnect(RegionBootstrap.java:113)
    at org.altbeacon.beacon.BeaconManager$BeaconServiceConnection.onServiceConnected(BeaconManager.java:785)
    at org.robolectric.shadows.ShadowApplication$1.run(ShadowApplication.java:236)
    at org.robolectric.util.Scheduler.runOrQueueRunnable(Scheduler.java:293)
    at org.robolectric.util.Scheduler.postDelayed(Scheduler.java:143)
    at org.robolectric.shadows.ShadowLooper.post(ShadowLooper.java:261)
    at org.robolectric.shadows.ShadowApplication.bindService(ShadowApplication.java:225)
    at org.robolectric.shadows.ShadowContextImpl.bindService(ShadowContextImpl.java:217)
    at android.app.ContextImpl.bindService(ContextImpl.java)
    at android.content.ContextWrapper.bindService(ContextWrapper.java:604)
    at org.altbeacon.beacon.startup.RegionBootstrap$InternalBeaconConsumer.bindService(RegionBootstrap.java:130)
    at org.altbeacon.beacon.BeaconManager.bind(BeaconManager.java:307)
    at org.altbeacon.beacon.startup.RegionBootstrap.<init>(RegionBootstrap.java:57)
    at com.myapp.MyApplication.onCreate(MyApplication.java:100)
    at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:165)
    at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:423)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:254)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:191)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:56)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:157)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

I think the problem come from this line https://github.com/AltBeacon/android-beacon-library/blob/master/src/main/java/org/altbeacon/beacon/BeaconManager.java#L308

Mobile device model and OS version

Nexus 5, Android 6.0.1

Android Beacon Library version

Version 2.8.1

Robolectric version

Version 3.1

speedingdeer commented 8 years ago

+1 I have exact the same problem, The same NullPointer and can't find a work around.

davidgyoung commented 8 years ago

Just so I understand the problem... The issue is that you want to use Robolectric in your app that uses the Android Beacon Library, but using RegionBootstrap in the onCreate method of your Application class prevents you from running tests because you get this exception, yes?

In the case highlighted here, this line of code throws a NullPointerException because in the Robolectric environment there is no way to send a message using the Android APIs: https://github.com/AltBeacon/android-beacon-library/blob/2.8.1/src/main/java/org/altbeacon/beacon/BeaconManager.java#L534

This isn't a super easy problem to solve. Understand that Robolectric is used by this library for internal unit tests allows a way to run tests without access to an Android device, provided the tests are designed to handle shortcomings like these. It isn't really designed to make itself easily testable with Robolectic, doing so would require one of two things:

  1. Add safety checks to prevent such exceptions from happening in production code. (This might be easier in the short-term, but it is fragile and will make production code more complex.)
  2. Build a Robolectric mock version of the BeaconManager that can be returned in the case of using Robolectric. This version would basically be an inert version o the BeaconManager that essentially does nothing, but allows all of its method calls to be made without throwing exceptions. (This is probably a better plan.)

If any of you are interested in working on this, I can provide a few thoughts on how it might be put together.

speedingdeer commented 8 years ago

David thanks for the the explanation. If you decide to keep this issue open, and you had time - drop your thoughts I will check if I'm able to come up with something valuable.

davidgyoung commented 8 years ago

@speedingdeer, my basic thought would be to:

I'm sure there would be complications, but a first cut at trying to build this probably wouldn't be so hard.

speedingdeer commented 8 years ago

thanks @davidgyoung, plan looks good.

kmenager commented 8 years ago

The issue is that you want to use Robolectric in your app that uses the Android Beacon Library, but using RegionBootstrap in the onCreate method of your Application class prevents you from running tests because you get this exception, yes?

Yes It's exactly that !

Thanks @davidgyoung, I will try to mock BeaconManager. Hope someone found a solution to this problem

mtjohnst commented 8 years ago

Hey @kmenager, I am having the same issue but I can't figure out how to mock BeaconManager. Have you had any luck doing this?