简体   繁体   中英

Writing a JUnit test to check SharedPreferences data

I am new to unit testing in Android and my attempt is to assertTrue that the data is successfully passed to a method and saved in SharedPreferences . This is my test so far:

public class AuthTest {

    Authorization authorization = new Authorization();

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

    @Test
    public void test_IfAuthIsSaved() {
        //test if the auth object is saved in the auth object is saved as a.. 
        //..json string in Shared preferences
        Auth auth = mock(Auth.class);
        authorization.saveAuth(auth);

        //test if the auth is received and saved to sharedpreferences
    }

}

saveAuth method:

public void saveAuth(Auth auth) {
    editor.putString("USER_AUTH", new Gson().toJson(auth));
    editor.commit();
}

What would the assertion look like for this?

You are mocking Auth which does not interact with anything in your code so you can't do any assertions on it.

You need to change your approach of testing:

1st Approach

  • Mock SharedPreferences.Editor and inject it inside Authorization .
  • Instantiate a new Auth object and invoke authorization.saveAuth(auth) .
  • Assert that editorMock.putString() is invoked with the expected json.
  • Assert that editorMock.commit() is invoked.

This approach has some drawbacks:

  • your test is coupled with the implementation.
  • if you decide to store the Auth data in some other kind of form you would need to change the test
  • you are not really testing behavior (which you actually want to do)

2nd Approach

  • Create a fake implementation of SharedPreferences.Editor and inject it inside Authorization .
  • Create a new Auth object and invoke authorization.saveAuth(auth) .
  • Retrieve auth after saving it by invoking authorization.getAuth() and assert that it is the same Auth that you saved.

Drawbacks: * you need to create a fake implementation of ``SharedPrefereces.Editor``` for test purposes that simulates the same behavior

Advantages: * your test is not coupled with the implementation * you are free to change the implementation without changing the test * you are testing behavior not methods

Some references to backup the second approach:

Now, from a technical point of view, retrieval of a stored object is really a subset of creation, since ...

Domain Driven Design by Eric Evans

You dont really need to mock the Auth class. Its more about the editor .

1) Move the new Gson().toJson(auth) into a separate package level method:

JSONObject toJson(Auth auth){
   return new Gson().toJson(auth);
}

2) The test:

public class AuthTest {
    @InjectMocks
    @Spy
    Authorization authorization;

    @Mock
    private Editor editorMock;

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

    @Test
    public void test_IfAuthIsSaved() {
        // Arrange
       JSONObject jsonO = mock(JSONObject.class);

        Auth auth = mock(Auth.class);
        doReturn(jsonO).when(authorization).toJson(auth);            

        // Act
        authorization.saveAuth(auth);

        // Assert
        verify(editorMock).putString(Mockito.eq("USER_AUTH"), Mockito.eq(jsonO));
        verify(editorMock).commit();
    }

}

I assume the editor is an instance field dependency;

What if Authorization constructor has SharedPrefrences.

val sharedPreferences = Mockito.mock(SharedPreferences::class.java)
val editor = Mockito.mock(SharedPreferences.Editor::class.java)
Mockito.`when`(sharedPreferences.edit()).thenReturn(editor)

val authorization = Authorization(sharedPreferences)
val auth = ...
authorization.saveAuth(auth)

verify(editor).putString(...)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM