I am unable to find Textview by id in test. What I do wrong?
private MyActivity myActivity;
#Before
public void setUp() throws Exception {
myActivity= Mockito.mock(MyActivity .class);
}
Test:
#Test
public void testFindView() throws Exception {
System.out.println(myActivity); // This is not null
this.myActivity.setContentView(R.layout.container);
TextView viewText = (TextView) this.myActivity.findViewById(R.id.container_text);
System.out.println(viewText ); // This is null
}
Calling Mockito.mock() doesn't create a real instance, but only an artificial one. It's main purpose is to keep unit tests away from any external dependencies and track interactions with an object.
So when you call this.myActivity.setContentView(R.layout.container); nothing really happens, because mocked myActivity doesn't have the insides of a regular MyActivity - you're only calling a stub method that you have not ordered to do anything.
So you need to create a real instance of MyActivity if you want to test how it works. You can also play with Spy objects if you still want to track interactions (you can check them out here)
Related
I'm testing an activity, and I want to mock getActionBar(). I've tried doing it the usual way, that is
ActionBar mActionBar;
#Before
public void setup() {
initMocks(this);
mActionBar = Mockito.mock(ActionBar.class);
}
#Test
public void someTest(){
when(activity.getActionBar()).thenReturn(mActionBar);
}
But that doesn't seem to do anything, because I still get an NPE, when I try using the action bar in the activity after getActionBar().
You are probably calling other methods on the mocked ActionBar in the code you are testing, like for example:
Tab tab = actionBar.getSelectedTab()
This returns null. Using tab then will result in a NPE.
This means you will need to mock more, for example:
when(actionBar.getSelectedTab()).thenReturn(mock(Tab.class));
Now the above example will return a mocked Tab.
I assume you're setting Activity as it is written in Robolectric tutorial. There is no simple way to mock real activity method inside of activity code itself.
I would suggest you create TestMyActivity that extends your activity and lives only in test sources. Then you can override getActionBar() (probably getSupportActionBar())).
public class TestMyActivity extends MyActivity {
#Override
ActionBar getActionBar() {
return mockedActionBar;
}
}
I have an Android app that I'm working on and trying to write unit tests for it. The app is written with the MVP architecture and I am trying to test the Presenter-class.
Simplified method I'm trying to test looks like this:
public void userPressedButton() {
service.loadData(new Callback<Data>{
#Override
onResponse(Data data) {
view.showData(data);
}
});
}
Now I want to verify that when the userPressedButton method is called view.showData(data) is called.
I have tried several approaches but I can't seem to figure out how to test this.
Any ideas?
Edit: to clarify, I want to write a unit test
Interesting case.
What i would do is to:
1) - Create a concrete class for that particular Callback:
public class MyCallback implements Callback<Data>{
private View view;
public MyCallback(View view){
this.view = view;
}
#Override
onResponse(Data data) {
view.showData(data);
}
}
Now for this class you can write a unit test which would check whether the onResponse method calls the showData method of the view field.
2) Having extacted the implementation to a concrete class, from the perspective of the class which contains the userPressedButton method, it really is not essential what happens inside of the Callback class.
It is important that a concrete implementation of that interface has been passed:
public void userPressedButton() {
service.loadData(new MyCallback(view));
}
and finally the test:
#InjectMocks
MyClass myClass;
#Mock
Service service;
#Captor
ArgumentCaptor argCaptor;
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
#Test
public void shouldUseMyCallback(){
// Arrange
// set up myClass for test
// Act
myClass.userPressedButton();
Mockito.verify(service).loadData(argCaptor.capture());
// Assert
assertTrue(argCaptor.getValue instance of MyCallback);
}
So we check whether the loadData method has been called with proper implementation.
Thats how i would test your case.
You could "store" the callback and use a test callback during your test
class YourClass {
private ??? view;
private Callback<Data> callback;
// for testing purposes
protected YouClass(Callback<Data> callback) {
this.callback = callback;
}
public YouClass() {
this(new Callback<Data>{
#Override
onResponse(Data data) {
view.showData(data);
}
});
}
public void userPressedButton() {
service.loadData(this.callback);
}
}
then use some custom callback for your test
Even more simple solution. If this is MVP, you can pass view instance to presenter class. Then test invocation on Mock.
This is what a test method would look like:
MVPView view = mock(MVPView.class);
Presenter presenter = new Presenter(view)
presenter.userPressedButton();
verify(view, atLeastOnce()).showData(any(Data.class));
If the call is asynchronious, then wait for the result, by modifying the last statement:
verify(view, timetout(5000).atLeastOnce()).showData(any(Data.class));
[UPDATE]:
I know what NPE is,but I don't know why it appears here.So I think this is totally not a duplicated question as What is a Null Pointer Exception, and how do I fix it?.But any way I have found the answer.To use Mockito in instrumented test,addition dependencies dexmaker and dexmaker-mockito are also required:
androidTestCompile "com.google.dexmaker:dexmaker:1.2"
androidTestCompile "com.google.dexmaker:dexmaker-mockito:1.2"
And if you don't run yout test under MockitoJUnitRunner,addition initialization is also required as below answer has mentioned:
MockitoAnnotations.initMocks(this);
See also Initialising mock objects - MockIto for futher discussion.
I want to write a simple test that checks if user's data is shown on the UI.The Activity retrieves the data stored in sharedPreferences within onResume() and shows it on the UI.The following is my code for the test:
#RunWith(AndroidJUnit4.class)
public class EditProfileActivityTest {
#Mock
private UserPreference userPreference;
private String FAKE_NAME = "Test";
#Rule
public ActivityTestRule<EditProfileActivity> activityTestRule = new ActivityTestRule(EditProfileActivity.class,true,false);
#Before
public void setUp(){
//Set fake SharedPreferences
when(userPreference.getName()).thenReturn(FAKE_NAME);
//Start Activity
Intent intent = new Intent();
activityTestRule.launchActivity(intent);
}
#Test
public void showUserData() throws Exception{
onView(withId(R.id.name_tv)).check(matches(withText(FAKE_NAME)));
}
}
where UserPreference is a custom class which simply wraps SharedPreference class and contains lots of getters and setters.This is its constructor
public UserPreference(Context context) {
this.context = context;
sharedPreferences = this.context.getSharedPreferences("Pref", Context.MODE_PRIVATE);
prefEditor = sharedPreferences.edit();
}
and one of its getter
public String getName() {
return sharedPreferences.getString(context.getString(R.string.pref_name), "Guest");
}
But when I run the test,it keeps showing NullPointerExceptiions on this line
when(userPreference.getName()).thenReturn(FAKE_NAME);
I've searched for related topics but I still can't see why.I think the concept of mock is to re-define a method's behavior no matter what the real implementation is. I am new to testing,so I am sorry in advance if this is a silly qustion.
By the way the test runs perfectly with the following code
#RunWith(AndroidJUnit4.class)
public class EditProfileActivityTest {
private UserPreference userPreference;
private String FAKE_NAME = "Test";
#Rule
public ActivityTestRule<EditProfileActivity> activityTestRule = new ActivityTestRule(EditProfileActivity.class,true,false);
#Before
public void setUp(){
//Start Activity
Intent intent = new Intent();
activityTestRule.launchActivity(intent);
}
#Test
public void showUserData() throws Exception{
onView(withId(R.id.name_tv)).check(matches(withText(FAKE_NAME)));
}
}
But the preference data it retrieves is from the "real" device.In this case i can't make an assertion about what will be displayed so I can't tell whether the test is passed.This is why I want to mock the preference to make it predictable.
You have to init your mocks in #Before like so:
public void setUp() {
MockitoAnnotations.initMocks(this);
// ...
}
Your userPreference object is null, but you're trying to call a method on it. If you post all of your code it will be easier.
The idea of a Mock object is correct - but you're not using a Mock object, you're calling when() on a real object, but which hasn't been created yet, thus the NPE.
I am using mockito to test the call to an Interface, but I get some problems when I want to verify that the interface method 'goToLoginInterface()' was called consecutively when I call to 'goToLogin()'. It is supposed to be something simple but I've been trying to find a solution for hours.
I put and assert to verify that 'getActivityParent()' is effectively returning the mock Interface object, and it is!, so I don't know what the problem is.
public class LoginSimpleFragment extends Fragment {
private ActivityInterface mParentActivity;
public interface ActivityInterface {
void goToLoginInterface();
}
public ActivityInterface getActivityInterface(){
return mParentActivity;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.login_simple, container, false);
}
public void goToLogin() {
getActivityInterface().goToLoginInterface();
}
}
This is my test class
#Config(manifest = "../app/src/main/AndroidManifest.xml", emulateSdk = 18)
#RunWith(RobolectricTestRunner.class) // <== REQUIRED for Robolectric!
public class TestLoginActivity {
#Test
public void testPositiveButtonAction() throws Exception {
LoginSimpleFragment mockLoginSampleFragment =
mock(LoginSimpleFragment.class);
LoginSimpleFragment.ActivityInterface mockInterface =
mock(LoginSimpleFragment.ActivityInterface.class);
Mockito.doNothing().when(mockInterface).goToLoginInterface();
//doReturn(mockInterface).when(mockLoginSampleFragment).getActivityInterface();
when(mockLoginSampleFragment.getActivityInterface()).thenReturn(mockInterface);
mockLoginSampleFragment.goToLogin();
assert( Mockito.mockingDetails(mockLoginSampleFragment.getActivityInterface()).isMock() );
verify(mockInterface).goToLoginInterface();
}
}
the output test said:
Wanted but not invoked:
activityInterface.goToLoginInterface();
-> at co.mobico.mainactivities.TestLoginActivity.testPositiveButtonAction(TestLoginActivity.java:35)
Actually, there were zero interactions with this mock.
TestLoginActivity.java:35 is the line 'verify(mockInterface).goToLoginInterface()', at the end of test function
Can you helpme to make the test pass?, I'm using TDD in Android with robolectric, so if I cannot get solve it, I cannot continue working, Thanks!
You are lost in a maze of mocks.
You're not actually using a LoginSampleFragment, you're using a Mock of that class. So when you call goToLogin(), nothing happens, because the mock won't run your normal class code.
Even if you would instruct your mock to do something when you call goToLogin(), at this point you aren't testing your code anymore, you're just testing your own mock setup, spinning in circles.
This might be a good reading: When should I mock?
I am trying to test using AndroidTestCase. I am trying to test only one particular class in my application, however this class does not extend Activity, Service or anything else. It is basically a plain Java class apart from the fact that it requires a Context. It is a pojo and some of its variables are objects that require android api calls in their creation, e.g. a call to the SensorManager.
I tried to use:
Context context = getContext();
When running my tests this gives me the exception "System services not available to activites before onCreate()". Does that method have to be overridden?
final Context context = new IsolatedContext(null, getContext()) gives the same thing.
The reason I am using the Android testing framework and not something like Robolectric is because the class I'm testing gathers hardware information about a device and so I want to run the tests on an actual device. I have looked at the developer docs for AndroidTestCase but can't see what I'm looking for in the examples. I'm not sure the other test case classes will achieve what I want. Any ideas?
My test class:
public class DeviceTest extends AndroidTestCase {
ClassToTest mClassToTest;
#Override
protected void setUp() throws Exception {
final Context context = new IsolatedContext(null, getContext()) {
#Override
public Object getSystemService(final String pName) {
return getContext().getSystemService(pName);
}
};
mClassToTest = new ClassToTest(context);
super.setUp();
}
public void testClassMethod() {
Object mObject;
mObject = mClassToTest.getObject();
assertNotNull(mObject);
}
#Override
protected void tearDown() throws Exception {
mClassToTest = null;
super.tearDown();
}
}
Thanks in advance.
UPDATE: After changing my setup to the following:
#Override
protected void setUp() throws Exception {
super.setUp();
context = this.getContext();
mClassToTest = new ClassToTest(context);
}
I am getting an error that context is null. In what scenarios would AndroidTestCase.getContext() return null? My setup seems to be ok....
From AndroidTestCase you can access directly mContext, or call getContext().
From the context returned by those, you could also call Context.getApplicationContext() if you wanted that one.
You can use mContext from super class (AndroidTestCase). I used it for the testing of the database where context is required.
AndroidTestCase.class
public class AndroidTestCase extends TestCase {
protected Context mContext;
...
}
You would be able to use Context in the inherited class of AndroidTestCase.
TestDb.java
public class TestDb extends AndroidTestCase {
void deleteTheDatabase() {mContext.deleteDatabase(DB_NAME)};
}
There are a few ways around this, you could use a mockcontext as one solution or if you really do not care what the context is just that is valid you can use an InstrumentationTestCase and get the context of the test apk via getInstrumentation().getContext().
I think the reason your context is null is that actually no android context exists at this point, you can get one by creating an application or an activity.