android - How do I make my activity use testing data? -
i have application displays data (posts) web api.
- a background service syncs data @ unknown time , saves it.
- when visiting main activity loads data , displays in recyclerview
- the loading handled via singleton class
i test main activity follows
@rule public activitytestrule<mainactivity> mactivityrule = new activitytestrule<>(mainactivity.class); @test public void testdataload() { int poststotal = datasingleton.getinstance().getpostscount(); viewinteraction empty = onview(withid(r.id.empty_view)); viewinteraction recycler = onview(withid(r.id.recycler_view)); if (poststotal == 0) { empty.check(matches(isdisplayed())); recycler.check(matches(not(isdisplayed()))); } else { empty.check(matches(not(isdisplayed()))); recycler.check(matches(isdisplayed())); recycler.check(new recyclerviewitemcountassertion(greaterthan(poststotal))); } }
i know can't right way write tests. want able test both empty data set , non-empty set if-else 2 separate tests. way think can achieve mock data.
is there way? can use mockito make mainactivity use mock data without modifying production code? choice make inject either real or mocked data providers in place of singleton?
is better uninstall , reinstall app each time there no data start , continue real data testing?
android activity heavyweight , hard test. because don't have control on constructor, hard swap in test doubles.
the first thing make sure depending on abstraction of data-source rather concretion. if using singleton getpostscount()
method extract interface:
interface datasourceabstraction { int getpostscount(); }
make wrapper class implements interface:
class concretedatasource implements datasourceabstraction { @override int getpostscount() { return datasingleton.getinstance().getpostscount(); } }
and make activity depend on rather concrete datasingleton
datasourceabstraction datasourceabstraction; @override protected void oncreate(bundle savedinstancestate) { super(savedinstancestate); injectmembers(); } @visiblefortesting void injectmembers() { datasourceabstraction = new concretedatasource(); }
you can swap in test double subclassing , overriding injectmembers
has relaxed visibility. it's bad idea in enterprise development, there less options in android activities don't control constructor of class.
you can write:
datasourceabstraction datasource; //system under test mainactivity mainactivity @before public void setup() { mockdatasource = mockito.mock(datasourceabstraction.class); mainactivity = new mainactivity() { @override void injectmembers() { datasourceabstraction = mockdatasource; } }; }
Comments
Post a Comment