How do I mock SQLiteDatabase instance? - android

In my class to be tested, I have this code in the constructor
public MyClass (Context context){
String db = context.getDatabasePath("mydb.db").getPath();
this.connection = SQLiteDatabase.openOrCreateDatabase(db, null);
}
mydb.db is located in src/test/resources
This is my test class
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
MyClass myClass;
#Mock
Context context;
#Mock
SQLiteDatabase sqLiteDatabase;
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
URL resource =this.getClass().getClassLoader().getResource("mydb.db");
File file = new File(resource.getPath());
doReturn(file).when(context).getDatabasePath("mydb.db");
myClass=new MyClass(context);
}
}
When running test, i've got the exception:
java.lang.RuntimeException: Method openOrCreateDatabase in android.database.sqlite.SQLiteDatabase not mocked. See http://g.co/androidstudio/not-mocked for details.
I've added this in my build.gradle
testOptions {
unitTests.returnDefaultValues = true
}
Now the exception got rid off.
but the connection of MyClass is null !
Is it possible to test this only using Mockito?

Related

Android HiltTest: The component was not created. Check that you have added the HiltAndroidRule

I have a util method which will go some actiivty by routing.
// RoutingUtil.java
public static void goRouting(Context context, String routing);
And I want test this method.
So I did something like this
#RunWith(AndroidJUnit4.class)
#HiltAndroidTest
public class RoutingUiUtilsTest {
#Rule
public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
#Before
public void setUp() {
hiltRule.inject();
}
#Test
public void testSmartGo() {
ActivityScenario.launch(MainActivity.class);
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
RoutingUtil.goRouting(context, "", "schema://a_activity_path");
}
}
The dest Activity is AActivity which used the hilt by annoutation #AndroidEntryPoint
#AndroidEntryPoint
class AActivity extends Activity {
}
Then I run test in terminal
./gradlew connectedAndroidTest
And error throws
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.somepackage/com.somepackage.AActivity}:
java.lang.IllegalStateException: The component was not created. Check
that you have added the HiltAndroidRule
I think the reason is I didn't start AActivity by hilt test componet, like ActivityScenario.launch(AActivity.class);, but what I want test is RoutingUtil.goRouting so I can't use hilt test component.
So how to test RoutingUtil.goRouting?

How to get mock telephonymanager service android

Actually i want to write some mock unit tests for telephony manger , i am using mockito framework to mock telephony service. I am returning particular operator name based on my configurations it is not working.
Context mockContext = mock(Context.class);
TelephonyManager mockTelephonyManager = mock(TelephonyManager.class);
when(mockContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mockTelephonyManager);
when(mockTelephonyManager.getNetworkOperatorName()).thenReturn("SomeNetwork");
assertTrue("SomeNetwork",some.getNetworkOperatorName());
// callling method
SomeClass some = new SomeClass();
some.getNetworkOperatorName();
class SomeClass{
public String getNetworkOperatorName(){
TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(TELEPHONY_SERVICE);
return telephonyManager.getNetworkOperatorName();
}
}
As I can see here is that mockContext dos not get injected to SomeClass instance.
You can either do it using constructor injection:
SomeClass(Context context) {
this.context = contest;
}
and in the test just initialize it like this:
SomeClass some = new SomeClass(mockContext);
Or you can use mockito annotations to create and inject mocks:
#Mock
private Context mockContext;
#InjectMocks
private SomeClass someClass;
#Test
public void test() {
TelephonyManager mockTelephonyManager = mock(TelephonyManager.class);
when(mockContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mockTelephonyManager);
when(mockTelephonyManager.getNetworkOperatorName()).thenReturn("SomeNetwork");
assertTrue("SomeNetwork",someClass.getNetworkOperatorName());
}
In this case, make sure to annotate your test class with #RunWith(MockitoJUnitRunner.class) or to call MockitoAnnotations.initMocks(this) method.
Either of this should work.

Mockito NullPointerException when object of Repository is created

public class DriveInteractor implements DriveContract.Interactor {
private final DriveRepository driveRepository;
public DriveInteractor(Context context) {
DriveApplication application = (DriveApplication) context.getApplicationContext();
this.driveRepository = application.getDriveRepository();
}
#Override
public List<Drive> getDrive() {
List<Drive> drives = driveRepository.getDrives();
return drives;
}
}
Following is the code for my Test Class for which I am using Mockito:
#RunWith(PowerMockRunner.class)
public class DriveInteractorTest {
#Mock
private Context context;
#Mock
private DriveRepository driveRepository;
#Mock
private List<Drive> driveList;
#Mock
private DriveApplication driveApplication;
private DriveInteractor driveInteractor;
#Before
public void setUpDriveInterator(){
MockitoAnnotations.initMocks(this);
driveInteractor = new DriveInteractor(context);
}
.....}
I have also written a test method in my Test Class. As soon as I run my test method I keep getting a Null Pointer Exception pointing towards DriveRepository.
I even tried creating an object of my Drive POJO class in setUpDriveInterator method and adding to the arraylist, but it doesn't work:
public class DriveRepository {
private List<Drive> drives;
public DriveRepository(Context context) {
drives = new ArrayList<>();
drives.add(Drive.create(context, "ABC", "Honda"));
.....
}
....}
Which context needs to be passed in DriveInterator for testing? Any help would be greatly appreciated.
stub your context.getApplicationContext(); piece of code in your test method.
something like below Mockito.when(context.getApplicationContext()).thenReturn(driveApplication);
Hope it is useful.

PowerMockito: Unable to mock a constructor if code is in another class

I am facing a very weird issue here.
Following is my Test class:
SearchViewModel.java
#RunWith(PowerMockRunner.class)
#PrepareForTest({JSONReader.class, ConstantsPath.class, DatabaseManager.class})
public class SearchViewModelTest {
#Rule
public TestRule rule = new InstantTaskExecutorRule();
private String indexSearchContent;
private String fullTextSearchContentGL1, fullTextSearchContentGL2, fullTextSearchContentGL3, fullTextSearchContentGL4;
private String searchQuery = "a";
private List<FullTextSearchItem> fullTextSearchResult;
private String behaviorString;
private SearchViewModel searchViewModel;
private DatabaseManager databaseManager;
private void initInputs() throws IOException {
indexSearchContent = JSONReader.convertStreamToString(getClass().getClassLoader().getResourceAsStream(ConstantsPath.getInstance().getIndexSearchFilePath()));
behaviorString = JSONReader.convertStreamToString(getClass().getClassLoader().getResourceAsStream(ConstantsPath.getInstance().getBehavioralFilePath()));
fullTextSearchContentGL1 = JSONReader.convertStreamToString(getClass().getClassLoader().getResourceAsStream(ConstantsPath.getInstance().getFullTextSearchFilePath("1")));
fullTextSearchContentGL2 = JSONReader.convertStreamToString(getClass().getClassLoader().getResourceAsStream(ConstantsPath.getInstance().getFullTextSearchFilePath("2")));
fullTextSearchContentGL3 = JSONReader.convertStreamToString(getClass().getClassLoader().getResourceAsStream(ConstantsPath.getInstance().getFullTextSearchFilePath("3")));
}
private void mockDaggerDependency() {
AppInfo appInfo = Mockito.mock(AppInfo.class);
Mockito.when(appInfo.getAppName()).thenReturn("testApp");
Mockito.when(appInfo.getAppLanguage()).thenReturn("EN");
TestApplicationModule module = new TestApplicationModule(appInfo);
DatabaseModule databaseModule = Mockito.mock(DatabaseModule.class);
Component component = DaggerComponent.builder().applicationModule(module).databaseModule(databaseModule).build();
MyApplication.setComponent(component);
}
private void mockGuidelineList() throws Exception {
databaseManager = PowerMockito.mock(DatabaseManager.class);
List<Guideline> mockedGls = new ArrayList<>();
Guideline gl = new Guideline();
gl.setGuidelineId("1");
mockedGls.add(gl);
gl = new Guideline();
gl.setGuidelineId("2");
mockedGls.add(gl);
gl = new Guideline();
gl.setGuidelineId("3");
mockedGls.add(gl);
Mockito.when(databaseManager.getGuidelinesListByPositionOnHome()).thenReturn(mockedGls);
PowerMockito.whenNew(DatabaseManager.class).withNoArguments().thenReturn(databaseManager);
// prepare expected output for fulltext search
Observable.fromIterable(new DatabaseManager().getGuidelinesListByPositionOnHome())
.map(Guideline::getGuidelineId)
.flatMap(glId -> BehavioralFile.<List<FullTextSearchItem>>loadJsonFile(ConstantsPath.getInstance().getFullTextSearchFilePath(glId),
new TypeToken<List<FullTextSearchItem>>() {
}.getType()).toObservable()
.flatMapIterable(fullTextSearchitems -> fullTextSearchitems)
.filter(item -> item.getText().toLowerCase().contains(searchQuery.toLowerCase()))).<List<FullTextSearchItem>>toList()
.subscribe(list -> {
fullTextSearchResult = list;
});
}
#Before
public void setUp() throws Exception {
MainActivityTest.overrideRxJavaPlugins();
mockDaggerDependency();
initInputs();
PowerMockito.mockStatic(JSONReader.class);
BDDMockito.given(JSONReader.readJsonFile(ConstantsPath.getInstance().getIndexSearchFilePath())).willReturn(indexSearchContent);
BDDMockito.given(JSONReader.readJsonFile(ConstantsPath.getInstance().getFullTextSearchFilePath("1"))).willReturn(fullTextSearchContentGL1);
BDDMockito.given(JSONReader.readJsonFile(ConstantsPath.getInstance().getFullTextSearchFilePath("2"))).willReturn(fullTextSearchContentGL2);
BDDMockito.given(JSONReader.readJsonFile(ConstantsPath.getInstance().getFullTextSearchFilePath("3"))).willReturn(fullTextSearchContentGL3);
BDDMockito.given(JSONReader.readJsonFile(ConstantsPath.getInstance().getBehavioralFilePath())).willReturn(behaviorString);
mockGuidelineList();
searchViewModel = new SearchViewModel();
}
#After
public void tearDown() throws Exception {
}
#Test
public void loadFullTextSearch() throws Exception {
//searchViewModel.loadFullTextSearch_(searchQuery);
loadFullTextSearch(searchQuery);
assertEquals(searchViewModel.fullTextSearchListLiveData.getValue().size(), fullTextSearchResult.size());
}
private void loadFullTextSearch(String query) {
// following line is throwing exception if put in another class.
Observable.fromIterable(new DatabaseManager().getGuidelinesListByPositionOnHome())
.map(Guideline::getGuidelineId)
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(Schedulers.io())
.flatMap(glId -> BehavioralFile.<List<FullTextSearchItem>>loadJsonFile(ConstantsPath.getInstance().getFullTextSearchFilePath(glId),
new TypeToken<List<FullTextSearchItem>>() {
}.getType()).toObservable()
.flatMapIterable(fullTextSearchitems -> fullTextSearchitems)
.filter(item -> item.getText().toLowerCase().contains(query.toLowerCase()))).<List<FullTextSearchItem>>toList().toObservable()
.subscribe(list -> searchViewModel.fullTextSearchListLiveData.setValue(list));
}
}
here loadFullTextSearch() test cases works perfectly fine until i remove comment of line searchViewModel.loadFullTextSearch_(searchQuery);,
check modified test case:
#Test
public void loadFullTextSearch() throws Exception {
searchViewModel.loadFullTextSearch_(searchQuery);
//loadFullTextSearch(searchQuery);
assertEquals(searchViewModel.fullTextSearchListLiveData.getValue().size(), fullTextSearchResult.size());
}
Here comes the weird part: both the functions(earchViewModel.loadFullTextSearch_(), loadFullTextSearch()) has same code but loadFullTestSearch_() is in SearchViewModel class and loadFullTextSearch() in is test cases it self, that i did to figure out why constructor of DatabaseManager class is not getting mocked(Observable.fromIterable(new DatabaseManager().getGuidelinesListByPositionOnHome())) when code is in SearchViewModel class.
Note: I am mocking constructor of DatabaseManager class. check mockGuidelineList() method. Mocked method is working if constructor is getting invoked in same test class.
Exception i get is :
java.lang.NullPointerException: Cannot return null from a non-#Nullable #Provides method
Because i am using dagger and the constructor i am mocking initialises database object dependency.
public DatabaseManager() {
MyApplication.getComponent().inject(this);
}
Any help would be appreciated, Thanks.
I was doing everything fine but missed to add class where constructor is being invoked in #PrepareForTest annotation.
So in my case this has to be:
#PrepareForTest({JSONReader.class, ConstantsPath.class, DatabaseManager.class, SearchViewModel.class})
this stackoverflow answer helped me out.

android unit test + robolectric 3.0 + java.lang.LinkageError: loader constraint violation

Error:
java.lang.LinkageError: loader constraint violation: when resolving
method "com.example.demo.utils.R.init(Landroid/content/Context;)V" the
class loader (instance of
org/robolectric/internal/bytecode/InstrumentingClassLoader) of the
current class, com/example/test/FirstTest, and the class loader
(instance of sun/misc/Launcher$AppClassLoader) for the method's
defining class, com/example/demo/utils/R, have different Class objects
for the type android/content/Context used in the signature
test code:
#runwith(RobolectricGradleTestRunner.class)
#config(constants = BuildConfig.class,sdk = 21,application = TestApplication.class)
public class FirstTest{
#test
public void testCase01(){
MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);
....
}
}
build.gradle:
dependencies {
testCompile 'junit:junit:4.12'
testCompile "org.robolectric:robolectric:3.0"
testCompile 'org.robolectric:shadows-httpclient:3.0'
...
}
src/test/java/.../TestApplication:
public class TestApplication extends Application {
}
com/example/demo/MainActivity:
public class MainActivity extends Activity {
#override
protected void onCreate(Bundle savedInstanceState) {
...
com.example.demo.utils.R.init(getApplicationContext());
...
}
}
com/example/demo/utils/R:
public final class R {
public static Resources resources;
private static String packageName;
public static void init(Context paramContext) {
resources = paramContext.getResources();
packageName = paramContext.getPackageName();
}
...
}
I find the reason why tests run fail is using a class named com.example.demo.utils.R, which has a conflict with an R class
autogenerated by the Android System. If you rename R to another name, like Ra, it works.

Categories

Resources