Skip to content Skip to sidebar Skip to footer

How To Mock A Android Nfc Tag Object For Unit Testing

I'm currently working on an Android project which needs NFC integration. Now I want to write some (j)unit tests to see if the application can receive NFC intents (specifically ACTI

Solution 1:

It's possible to create a mock tag object instance using reflection (note that this is not part of the public Android SDK, so it might fail for future Android versions).

  1. Get the createMockTag() method though reflection:

    Class tagClass = Tag.class;
    Method createMockTagMethod = tagClass.getMethod("createMockTag", byte[].class, int[].class, Bundle[].class);
    
  2. Define some constants for preparing the mock tag instance:

    finalintTECH_NFC_A=1;
    finalStringEXTRA_NFC_A_SAK="sak";    // short (SAK byte value)finalStringEXTRA_NFC_A_ATQA="atqa";  // byte[2] (ATQA value)finalintTECH_NFC_B=2;
    finalStringEXTRA_NFC_B_APPDATA="appdata";    // byte[] (Application Data bytes from ATQB/SENSB_RES)finalStringEXTRA_NFC_B_PROTINFO="protinfo";  // byte[] (Protocol Info bytes from ATQB/SENSB_RES)finalintTECH_ISO_DEP=3;
    finalStringEXTRA_ISO_DEP_HI_LAYER_RESP="hiresp";  // byte[] (null for NfcA)finalStringEXTRA_ISO_DEP_HIST_BYTES="histbytes";  // byte[] (null for NfcB)finalintTECH_NFC_F=4;
    finalStringEXTRA_NFC_F_SC="systemcode";  // byte[] (system code)finalStringEXTRA_NFC_F_PMM="pmm";        // byte[] (manufacturer bytes)finalintTECH_NFC_V=5;
    finalStringEXTRA_NFC_V_RESP_FLAGS="respflags";  // byte (Response Flag)finalStringEXTRA_NFC_V_DSFID="dsfid";           // byte (DSF ID)finalintTECH_NDEF=6;
    finalStringEXTRA_NDEF_MSG="ndefmsg";              // NdefMessage (Parcelable)finalStringEXTRA_NDEF_MAXLENGTH="ndefmaxlength";  // int (result for getMaxSize())finalStringEXTRA_NDEF_CARDSTATE="ndefcardstate";  // int (1: read-only, 2: read/write, 3: unknown)finalStringEXTRA_NDEF_TYPE="ndeftype";            // int (1: T1T, 2: T2T, 3: T3T, 4: T4T, 101: MF Classic, 102: ICODE)finalintTECH_NDEF_FORMATABLE=7;
    
    finalintTECH_MIFARE_CLASSIC=8;
    
    finalintTECH_MIFARE_ULTRALIGHT=9;
    finalStringEXTRA_MIFARE_ULTRALIGHT_IS_UL_C="isulc";  // boolean (true: Ultralight C)finalintTECH_NFC_BARCODE=10;
    finalStringEXTRA_NFC_BARCODE_BARCODE_TYPE="barcodetype";  // int (1: Kovio/ThinFilm)
  3. Create the tech-extras bundle for your tag type. For instance, for an NFC-A tag with an NDEF message:

    BundlenfcaBundle=newBundle();
    nfcaBundle.putByteArray(EXTRA_NFC_A_ATQA, newbyte[]{ (byte)0x44, (byte)0x00 }); //ATQA for Type 2 tag
    nfcaBundle.putShort(EXTRA_NFC_A_SAK , (short)0x00); //SAK for Type 2 tagBundlendefBundle=newBundle();
    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 tagNdefMessagemyNdefMessage= ...; // create an NDEF message
    ndefBundle.putParcelable(EXTRA_NDEF_MSG, myNdefMessage);  // add an NDEF message
  4. Prepare an anti-collision identifier/UID for your tag (see Tag.getId() method). E.g. a 7-byte-UID for a Type 2 tag:

    byte[] tagId = newbyte[] { (byte)0x3F, (byte)0x12, (byte)0x34, (byte)0x56, (byte)0x78, (byte)0x90, (byte)0xAB };
    
  5. Then you can create a mock tag instance by invoking the createMockTag() method

    Tag mockTag = (Tag)createMockTagMethod.invoke(null,
            tagId,                                     // tag UID/anti-collision identifier (see Tag.getId() method)newint[] { TECH_NFC_A, TECH_NDEF },       // tech-listnew Bundle[] { nfcaBundle, ndefBundle });  // array of tech-extra bundles, each entry maps to an entry in the tech-list

Once you created that mock tag object, you can send it as part of an NFC discovery intent. E.g. for a TECH_DISCOVERED intent:

IntenttechIntent=newIntent(NfcAdapter.ACTION_TECH_DISCOVERED);
techIntent.putExtra(NfcAdapter.EXTRA_ID, tagId);
techIntent.putExtra(NfcAdapter.EXTRA_TAG, mockTag);
techIntent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, newNdefMessage[]{ myNdefMessage });  // optionally add an NDEF message

You can then send this intent to your activity:

techIntent.setComponent(...); // or equivalent to optionally set an explicit receiverstartActivity(techIntent);

The receiver can even use the mock tag object to retrieve instances of the technology classes. However, any method that requires IO operations will fail.

Solution 2:

I don't think it is possible to mock these intents as these are fired by NFCService and without system permissions it is not possible to fire these intents and currently there is not support in the android framework to mock nfc tags.

Post a Comment for "How To Mock A Android Nfc Tag Object For Unit Testing"