I'm trying to define a subclass of SQLiteCursor, in order to redefine some of its functions (I'm using fillWindow as an example). However, I'm getting a few problems with the database functions.
The code in the method below was copied from the source fo SQLiteCursor (I just removed some junk for the sake of this question).
package com.malabarba.util;
import android.database.CursorWindow;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteCursor;
import android.database.sqlite.SQLiteCursorDriver;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteQuery;
import android.util.Log;
public class HugeCursor extends SQLiteCursor {
private SQLiteQuery mQuery;
public HugeCursor(SQLiteDatabase db, SQLiteCursorDriver driver, String editTable, SQLiteQuery query, int c) {
super(db, driver, editTable, query);
mQuery = query;
}
private void fillWindow(int requiredPos) {
int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos, 0);
mQuery.fillWindow(mWindow, startPos, requiredPos, false);
mCursorWindowCapacity = mWindow.getNumRows();
}
}
All the problems seem related to methods not being found:
The method cursorPickFillWindowStartPosition(int, int) is undefined for the type DatabaseUtils.
The method fillWindow(CursorWindow, int, int, boolean) is undefined for the type SQLiteQuery.
Both the functions in items 1 and 2 are defined and not private, so why can't I use them?
I think you are looking at some old-ish code. fillWindow() is now protected. Not sure what's going on with the DatabaseUtils one though.
Related
With AndroidX the InstrumentationRegistry is now deprecated. The documentation states
This method is deprecated. In most scenarios, getApplicationContext() should be used instead of the instrumentation test context. If you do need access to the test context for to access its resources, it is recommended to use getResourcesForApplication(String) instead.
However, I cannot find any examples of how to obtain the instance of PackageManager in test to invoke getResourcesForApplication and which package name should be provided to its string parameter.
For instance, here is the code that currently works:
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
import java.io.InputStream;
import androidx.test.InstrumentationRegistry;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import static org.junit.Assert.*;
#RunWith(AndroidJUnit4.class)
public class MyTest {
#Test
public void processImage() {
// load image from test assets
AssetManager am = InstrumentationRegistry.getContext().getAssets();
InputStream is = null;
Bitmap image = null;
try {
is = am.open("image.jpg");
image = BitmapFactory.decodeStream(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
if ( is != null ) {
try {
is.close();
} catch (IOException ignored) { }
}
}
assertNotNull(image);
// do something with the image
}
}
Now, how to rewrite this test without using the deprecated InstrumentationRegistry.getContext()? Keep in mind that image.jpg is not part of the application's assets - it's located in src/androidTest/assets folder and gets packaged into AppName-buildType-androidTest.apk (it's not present in the AppName-buildType.apk, for which I know the package name).
How to deduce the package name of the test APK? Is it possible to avoid hardcoding package name strings in my unit test? I am looking for a solution that is as elegant as the original code, but does not use deprecated methods.
I think you should simply use InstrumentationRegistry.getInstrumentation().getContext().getAssets() instead of InstrumentationRegistry.getContext().getAssets().
It will use your test context, so you should get your assets.
I'm using Green Coffee library to run Cucumber scenarios in my instrumentation tests. I followed example provided by repo step-by-step, but here's the error:
junit.framework.AssertionFailedError: Class pi.survey.features.MembersFeatureTest has no public constructor TestCase(String name) or TestCase()
And when I try to add default constructor to the class like provided here, it says
no default constructor available in
'com.mauriciotogneri.greencoffee.GreenCoffeeTest'
Here's my test's source code:
package pi.survey.features;
import android.support.test.rule.ActivityTestRule;
import com.mauriciotogneri.greencoffee.GreenCoffeeConfig;
import com.mauriciotogneri.greencoffee.GreenCoffeeTest;
import com.mauriciotogneri.greencoffee.Scenario;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.io.IOException;
import pi.survey.MainActivity;
import pi.survey.steps.memberSteps;
#RunWith(Parameterized.class)
public class MembersFeatureTest extends GreenCoffeeTest {
#Rule
public ActivityTestRule<MainActivity> activity = new ActivityTestRule<>(MainActivity.class);
public MembersFeatureTest(Scenario scenario) {
super(scenario);
}
#Parameterized.Parameters
public static Iterable<Scenario> scenarios() throws IOException {
return new GreenCoffeeConfig()
.withFeatureFromAssets("assets/members.feature")
.scenarios();
}
#Test
public void test() {
start(new memberSteps());
}
}
And my members.feature source:
Feature: Inserting info to server
Scenario: Invalid members
When I introduce an invalid members
And I press the login button
Then I see an error message saying 'Invalid members'
Regarding the questions about the constructors. Due to the fact that tests in GreenCoffee require:
#RunWith(Parameterized.class)
The static method annotated with #Parameters must return a list of something (but not necessarily Scenario). The examples in the documentation simply return a list of scenarios, that's why the constructor must take a single Scenario as a parameter.
However, you can create a class that encapsulates the scenario and other objects that you may need to pass to the constructor. For example, given the following class:
public class TestParameters
{
public final String name;
public final Scenario scenario;
public TestParameters(String name, Scenario scenario)
{
this.name = name;
this.scenario = scenario;
}
}
You can write:
public TestConstructor(TestParameters testParameters)
{
super(testParameters.scenario);
}
#Parameters
public static Iterable<TestParameters> parameters() throws IOException
{
List<TestParameters> testParametersList = new ArrayList<>();
List<Scenario> scenarios = new GreenCoffeeConfig()
.withFeatureFromAssets("...")
.scenarios();
for (Scenario scenario : scenarios)
{
testParametersList.add(new TestParameters(scenario.name(), scenario));
}
return testParametersList;
}
In this way you can receive multiple values (encapsulated in an object) in the test constructor.
Solved problem by just fixing the structure.
code details in this commit
So I am looking at the mocking objects in a test.
However the following test will return npe when " Mockito.when(mock.getName()" portion of code is executed, thats because the mock object is returned as null.
package com.example.activity;
import com.example.BuildConfig;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;
import static org.junit.Assert.assertTrue;
#RunWith(RobolectricGradleTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 21)
#PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
#PrepareForTest(Static.class)
public class DeckardActivityTest {
#Rule
public PowerMockRule rule = new PowerMockRule();
#Mock
public ToBeMocked mock;
#Test
public void testSomething() throws Exception {
assertTrue(Robolectric.buildActivity(DeckardActivity.class).create().get() != null);
}
#Test
public void testStaticMocking() {
PowerMockito.mockStatic(Static.class);
Mockito.when(Static.staticMethod()).thenReturn(mock);
Mockito.when(mock.getName()).thenReturn("Mock");
assertTrue(Static.getResp().equals("Mock"));
}
}
and the simple class we are testing
package com.example.activity;
public class Static {
private static ToBeMocked toBeMocked;
public static ToBeMocked staticMethod() {
toBeMocked = new ToBeMocked();
return toBeMocked;
}
public static String getResp(){
return toBeMocked.getName();
}
}
So my understanding must be wrong.
What I would like to do is mock out the ToBeMocked class dependency give it and tell the mock object how to respond when getName method is called on it.
Can some one help me as to why this is going wrong or point out what I must have misunderstood
Yes, you understand it wrong. I mean you have misunderstanding how mocks work.
Your method getResp (in example) uses internal states which will not be set at all, because after you call PowerMockito.mockStatic(Static.class); all calls of static methods of the Static.class will be intercepted. So the code:
toBeMocked = new ToBeMocked();
return toBeMocked;
never is called.
If the getResp uses the staticMethod() then you code will work.
public static String getResp(){
return staticMethod().getName();
}
So you have two option to resolve your issue:
refactor your code as I pointed
use mock constructor to mock toBeMocked = new ToBeMocked();
I am trying to write a backend service in Android, which reads a remote database and executes a query on it, returning the result in a ResultSet object. This is the code for my Java Bean which I return from the API call (called SQLResult):
package com.gradai.rushhour.backend;
import java.sql.ResultSet;
public class SQLResult
{
ResultSet result;
public SQLResult()
{
}
public ResultSet getResult()
{
return result;
}
public void setResult(ResultSet rs)
{
result = rs;
}
}
Now I try to use this API (called sqlBackend) in an AsyncTask in the actual app. In the onPostExecute function, I am getting an error:
error: incompatible types: com.gradai.rushhour.backend.sqlBackend.model.ResultSet cannot be converted to java.sql.ResultSet
This is the code for the said function:
protected void onPostExecute(SQLResult result)
{
ResultSet rs = result.getResult();
Toast toast = Toast.makeText(context, rs.toString(), Toast.LENGTH_LONG);
toast.show();
}
I don't get why is a ResultSet class being created in the backend model. Please help me in understanding what is going on. I'll be glad to provide further code if needed for debugging.
EDIT: These are the import statements used in the AsyncTask program:
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.json.gson.GsonFactory;
import com.gradai.rushhour.backend.sqlBackend.SqlBackend;
import com.gradai.rushhour.backend.sqlBackend.model.SQLResult;
import java.io.IOException;
import java.sql.ResultSet;
Also, please note that: I tried to convert the ResultSet in the API function to an ArrayList, and changed the SQLResult class to contain the same. Now, when I try to access the ArrayList in the same function, I get the error that a List is expected instead of an ArrayList. Could that be helpful?
I using Spring Android Rest Template to perform HTTP request. I was testing like so :
package com.mnubo.platform.android.sdk.internal.user.services.impl;
import com.mnubo.platform.android.sdk.models.users.User;
import org.junit.Before;
import org.junit.Test;
import org.springframework.test.web.client.MockRestServiceServer;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
#RunWith(RobolectricTestRunner.class)
#Config(emulateSdk = 18)
public class DummyTest {
private MyApiImpl myApi;
private MockRestServiceServer myapiMockServer;
#Before
public void setUp() throws Exception {
myApi = new MyApiImpl("ACCESS_TOKEN");//break here
myapiMockServer = MockRestServiceServer.createServer(myApi.getRestTemplate());
}
#Test
public void testRestClient() throws Exception {
final User expectedUser = new User();
expectedUser.setUsername("test");
expectedUser.setLastname("lastname");
myapiMockServer.expect(requestTo("http://my-service.com/user/test"))
.andExpect(method(GET))
.andRespond(withSuccess(this.convertToJsonString(expectedUser), APPLICATION_JSON_UTF8));
User user = myApi.userOperations().getUser("test");
userMockServer.verify();
}
}
All of this was working correctly using the RoboelectricTestRunner. But, yesterday Android Studio updated and asked me to update the build tool version to 1.1.0. (com.android.tools.build:gradle:1.1.0).
This version now include supports for Unit testing. See https://sites.google.com/a/android.com/tools/tech-docs/unit-testing-support
The problem : I can't create MyApiImpl anymore because it creates a RestTemplate. This RestTemplate use org.springframework.http.client.HttpComponentsClientHttpRequestFactory and in this class constructor, methods from the org.apache.http package are used.
These methods raised an exception : Eg: Method getSocketFactory in org.apache.http.conn.scheme.PlainSocketFactory
Well, I mocked successfully the getSocketFactory using PowerMock but then I had to mock the register method of SchemeRegistry that is only locally accessible from the constructor (source).
So I gave up trying to mock all of the shenanigans happening inside the RestTemplate and decided to directly mock the RestTemplate.
I need help to mock it correctly so that the MockRestServiceServer can still be used in my test, because right now, the myapiMockServer.verify() assertion fails.
Update
I'm still unable to use the MockRestServiceServer to test my Api, but I managed to test each individual OperationImpl using a mock of the RestTemplate like so :
public class DummyOperationTest {
private DummyOperation dummyOperation;
private RestTemplate mockedRestTemplate = mock(RestTemplate.class);
#Before
public void setUp() throws Exception {
super.setUp();
dummyOperation = new DummyOperationImpl(PLATFORM_BASE_URL, mockedRestTemplate);
}
#Test
public void test() throws Exception {
String calledUrl = PLATFORM_BASE_URL + "/objects?update_if_exists=true";
when(mockedRestTemplate.postForObject(calledUrl, expectedSmartObject, SmartObject.class)).thenReturn(expectedSmartObject);
smartObjectService.create(expectedSmartObject, true);
verify(mockedRestTemplate, atMost(1)).postForObject(calledUrl, expectedSmartObject, SmartObject.class);
}
}
Unfortunately, this still doesn't test the whole request execution. I can't validate that oAuth authentication is correctly added to the headers, or if the conversion of the server response is correct.
Well, it was a matter of mocking. I didn't understood everything correctly but I finally worked it out. Here is an a example that shows how to proceed :
package com.mnubo.platform.android.sdk.internal;
import android.util.Log;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.test.web.client.MockRestServiceServer;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.mockito.PowerMockito.whenNew;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
#RunWith(PowerMockRunner.class)
#PrepareForTest({
Log.class,
PlainSocketFactory.class,
SSLSocketFactory.class,
HttpComponentsClientHttpRequestFactory.class,
ConnManagerParams.class,
AbstractHttpClient.class
})
public class DummyTest {
private final String USER_ACCESS_TOKEN = "user_token";
private final PlainSocketFactory mockedPlainSocketFactory = mock(PlainSocketFactory.class);
private final SSLSocketFactory mockedSSLSocketFactory = mock(SSLSocketFactory.class);
private final SchemeRegistry mockedSchemeRegistry = mock(SchemeRegistry.class);
private final DefaultHttpClient mockedHttpClient = mock(DefaultHttpClient.class);
private final HttpParams mockedHttpParams = mock(HttpParams.class);
private DummyApiImpl dummyApi = new DummyApiImpl(USER_ACCESS_TOKEN);
protected MockRestServiceServer mockServer;
#Before
public void setUp() throws Exception {
mockStatic(Log.class);
mockStatic(PlainSocketFactory.class);
mockStatic(SchemeRegistry.class);
mockStatic(SSLSocketFactory.class);
mockStatic(ConnManagerParams.class);
whenNew(SchemeRegistry.class).withAnyArguments().thenReturn(mockedSchemeRegistry);
whenNew(DefaultHttpClient.class).withAnyArguments().thenReturn(mockedHttpClient);
when(PlainSocketFactory.getSocketFactory()).thenReturn(mockedPlainSocketFactory);
when(SSLSocketFactory.getSocketFactory()).thenReturn(mockedSSLSocketFactory);
when(mockedHttpClient.getParams()).thenReturn(mockedHttpParams);
mockServer = MockRestServiceServer.createServer(dummyApi.getRestTemplate());
}
#Test
public void doOperationTest() throws Exception {
final User testUser = new User();
mockUserServiceServer.expect(requestTo(expectedUrl("/users/test")))
.andExpect(method(POST))
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andRespond(withSuccess());
dummyApi.userOperations().createUser("test", testUser);
mockUserServiceServer.verify();
}
}
The problem occurred when the constructor of the Api was called. This classe extends AbstractOAuth2ApiBinding which constructor create a RestTemplate. This is this object that requires multiple level of mocking.
Once you have mocked the required element to create the RestTemplate, the rest is very easy, thanks to the mock server!