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.
Related
Currently I'm using MockK library (version 1.8.1) for unit tests in Android Dev, and I the problem is I can't mock Patterns.EMAIL_ADDRESS.
Test cases throw NPE every time this property gets invoked.
I tried mockkStatic(Patterns::class), but #Before method crashes with NPE while applying the rule every { Patterns.EMAIL_ADDRESS.pattern() } returns EMAIL_REGEX_STRING.
Class I'm trying to test:
public class EmailValidator {
private static final String EMPTY = "";
private final Context context;
#Inject
public EmailValidator(Context context) {
this.context = context;
}
public String isValidEmail(String email) {
if (StringUtils.isEmpty(email)) {
return context.getString(R.string.sign_up_error_email_empty);
}
if (!email.matches(Patterns.EMAIL_ADDRESS.pattern())) {
return context.getString(R.string.sign_up_error_email_validate);
}
return EMPTY;
}}
Try using
PatternsCompat.EMAIL_ADDRESS.pattern()
instead of just
Patterns.EMAIL_ADDRESS.pattern()
that did the job for me.
Instead of using Patterns.EMAIL_ADDRESS directly, you could create a wrapper around it then mock or fake the wrapper.
The wrapper could be a method, like:
class EmailValidator {
fun isValidEmail(email: String) {
if (StringUtils.isEmpty(email)) {
return context.getString(R.string.sign_up_error_email_empty);
}
if (!email.matches(getEmailPattern())) {
return context.getString(R.string.sign_up_error_email_validate);
}
}
private fun getEmailPattern(): String = Patterns.EMAIL_ADDRESS.pattern()
}
and your test could mock it like:
#Test
fun `test email validator`() {
val validator = spyk(EmailValidator())
every { validator["getEmailPattern"]() } returns yourTestPattern
assertThat(validator.isValidEmail("blah blah blah")).isFalse()
}
Or create a class that wraps it, maybe a PatternFactory class
class PatternFactory {
fun getEmailPattern(): String = ...
fun getVinPattern(): String = ...
}
then pass in PatternFactory in as a dependency and mock it for the test
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.
I create a unit test for my Presenter. My Presenter implements Listener callback if successfully load data from API (use Interactor):
PresenterTest.java
public class MainContactPresenterTest {
#Mock LoadContactInteractor loadContactInteractor;
#Mock ApiService apiService;
#Mock LoadContactView loadContactView;
#Mock ContactRepository contactRepository;
#Mock LoadContactInteractor.OnLoadDataFinishedListener listener;
#InjectMocks MainContactPresenterImpl presenter;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void getContactLists() {
// given
// when
presenter.fetchRemoteContacts();
// then
Mockito.verify(loadContactInteractor).onLoadData(listener);
}
}
Here is my Presenter:
public class MainContactPresenterImpl implements MainContactPresenter,
LoadContactInteractor.OnLoadDataFinishedListener {
private LoadContactView loadContactView;
private LoadContactInteractor loadContactInteractor;
private ContactRepository contactRepository;
#Inject
public MainContactPresenterImpl(LoadContactInteractor loadContactInteractor,
#NonNull LoadContactView loadContactView,
ContactRepository contactRepository) {
this.loadContactView = loadContactView;
this.loadContactInteractor = loadContactInteractor;
this.contactRepository = contactRepository;
}
#Override
public void onSuccessLoad(List<Contact> contacts) {
loadContactView.saveDataToLocalStorage(contacts);
}
#Override
public void onErrorLoad() {
loadContactView.dismissProgress();
loadContactView.showErrorMessage();
}
#Override
public void preCheckCacheData() {
if (contactRepository.getContactCount() == 0) {
// Load contacts from Server
fetchRemoteContacts();
} else {
fetchLocalContacts();
}
}
#Override
public void fetchRemoteContacts() {
loadContactView.showProgress();
loadContactInteractor.onLoadData(this);
}
}
But when I ran test, I got the mocking parameter in verify not match.
I got my presenter that have to be an argument. Not the listener.
Argument(s) are different! Wanted:
loadContactInteractor.onLoadData(
listener
);
Actual invocation has different arguments:
loadContactInteractor.onLoadData(
fanjavaid.gojek.com.contacts.presenter.MainContactPresenterImpl#1757cd72
);
How to handle that? Thank you
You are creating a mock...
#Mock LoadContactInteractor.OnLoadDataFinishedListener listener;
...and then you don't use it ever again and act suprised when verify tells you, that it wasn't actually used. Why? Of course it wasn't used, since you never use it anywhere, so how should your classes know to use that mock object?
Your MainContactPresenterImpl does not use an OnLoadDataFinishedListener as an external dependency (then your could perhaps inject it via #InjectMocks), it is itself such a listener and thus mocking another listener makes no sense here.
In other words, MainContactPresenterImpl has no OnLoadDataFinishedListener field, so Mockito is of course not capable of injecting something in this non-existing field. For something like this to work, you would need to add such a field and then use the content of that field when calling your onLoadData method.
The only invocation of your method is here...
loadContactInteractor.onLoadData(this);
And what is this in that context? It's the MainContactPresenterImpl object that contains the method, in other words, your presenter.
So, what will work is...
Mockito.verify(loadContactInteractor).onLoadData(presenter);
I have a problem with the dependency services for implementing features that depends of the plattorm. I need what my implementation on Android receive a Context object to do the task. How can I do it?
This is my code:
1) On PCL:
public interface ICallService
{
List<string> GetContacts();
}
2) On Android Project:
[assembly: Dependency(typeof(CallService))]
namespace DEMOBLOBS.Droid.DependencyServicesPruebas
{
public class CallService : ICallService
{
public static void Init() { }
public List<string> GetContacts()
{
AT THIS POINT I NEED THE CONTEXT OBJECT!
}
}
}
The constructor of Call Service class does not have any parameter. Maybe I can I pass the Context object like parameter in some way?
Can you help me, please?
you could try answer from https://forums.xamarin.com/discussion/106938/context-is-obsolete-as-of-version-2-5
internal static MainActivity Instance { get; private set; }
protected override void OnCreate(Bundle bundle)
{
Instance = this;
// Forms initialization here...
}
//later where you need it:
var context = MainActivity.Instance;
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?