How to mock a Android NFC Tag object for unit testing -
i'm working on android project needs nfc integration. want write (j)unit tests see if application can receive nfc intents (specifically action_tech_discovered
) , put given tag (in nfcadapter.extra_tag
) on bus system. surprise cannot create tag
instance or mock one. can explain me how can (unit) test?
at point accept form of integration testing, process of:
- detect nfc intent
- get
tag
object - put on bus wrapped in
carddetectedevent
.
i have phone nfc enabled , few cards testing.
android sdk version: 19
libraries used: robolectric, junit , mockito
it's possible create mock tag object instance using reflection (note not part of public android sdk, might fail future android versions).
get
createmocktag()
method though reflection:class tagclass = tag.class; method createmocktagmethod = tagclass.getmethod("createmocktag", byte[].class, int[].class, bundle[].class);
define constants preparing mock tag instance:
final int tech_nfc_a = 1; final string extra_nfc_a_sak = "sak"; // short (sak byte value) final string extra_nfc_a_atqa = "atqa"; // byte[2] (atqa value) final int tech_nfc_b = 2; final string extra_nfc_b_appdata = "appdata"; // byte[] (application data bytes atqb/sensb_res) final string extra_nfc_b_protinfo = "protinfo"; // byte[] (protocol info bytes atqb/sensb_res) final int tech_iso_dep = 3; final string extra_iso_dep_hi_layer_resp = "hiresp"; // byte[] (null nfca) final string extra_iso_dep_hist_bytes = "histbytes"; // byte[] (null nfcb) final int tech_nfc_f = 4; final string extra_nfc_f_sc = "systemcode"; // byte[] (system code) final string extra_nfc_f_pmm = "pmm"; // byte[] (manufacturer bytes) final int tech_nfc_v = 5; final string extra_nfc_v_resp_flags = "respflags"; // byte (response flag) final string extra_nfc_v_dsfid = "dsfid"; // byte (dsf id) final int tech_ndef = 6; final string extra_ndef_msg = "ndefmsg"; // ndefmessage (parcelable) final string extra_ndef_maxlength = "ndefmaxlength"; // int (result getmaxsize()) final string extra_ndef_cardstate = "ndefcardstate"; // int (1: read-only, 2: read/write, 3: unknown) final string extra_ndef_type = "ndeftype"; // int (1: t1t, 2: t2t, 3: t3t, 4: t4t, 101: mf classic, 102: icode) final int tech_ndef_formatable = 7; final int tech_mifare_classic = 8; final int tech_mifare_ultralight = 9; final string extra_mifare_ultralight_is_ul_c = "isulc"; // boolean (true: ultralight c) final int tech_nfc_barcode = 10; final string extra_nfc_barcode_barcode_type = "barcodetype"; // int (1: kovio/thinfilm)
create tech-extras bundle tag type. instance, nfc-a tag ndef message:
bundle nfcabundle = new bundle(); nfcabundle.putbytearray(extra_nfc_a_atqa, new byte[]{ (byte)0x44, (byte)0x00 }); //atqa type 2 tag nfcabundle.putshort(extra_nfc_a_sak , (short)0x00); //sak type 2 tag bundle ndefbundle = new bundle(); ndefbundle.putint(extra_ndef_maxlength, 48); // maximum message length: 48 bytes ndefbundle.putint(extra_ndef_cardstate, 1); // read-only ndefbundle.putint(extra_ndef_type, 2); // type 2 tag ndefmessage myndefmessage = ...; // create ndef message ndefbundle.putparcelable(extra_ndef_msg, myndefmessage); // add ndef message
prepare anti-collision identifier/uid tag (see
tag.getid()
method). e.g. 7-byte-uid type 2 tag:byte[] tagid = new byte[] { (byte)0x3f, (byte)0x12, (byte)0x34, (byte)0x56, (byte)0x78, (byte)0x90, (byte)0xab };
then can create mock tag instance invoking
createmocktag()
methodtag mocktag = (tag)createmocktagmethod.invoke(null, tagid, // tag uid/anti-collision identifier (see tag.getid() method) new int[] { tech_nfc_a, tech_ndef }, // tech-list new bundle[] { nfcabundle, ndefbundle }); // array of tech-extra bundles, each entry maps entry in tech-list
once created mock tag object, can send part of nfc discovery intent. e.g. tech_discovered
intent:
intent techintent = new intent(nfcadapter.action_tech_discovered); techintent.putextra(nfcadapter.extra_id, tagid); techintent.putextra(nfcadapter.extra_tag, mocktag); techintent.putextra(nfcadapter.extra_ndef_messages, new ndefmessage[]{ myndefmessage }); // optionally add ndef message
you can send intent activity:
techintent.setcomponent(...); // or equivalent optionally set explicit receiver startactivity(techintent);
the receiver can use mock tag object retrieve instances of technology classes. however, method requires io operations fail.
Comments
Post a Comment