I am writing unit test cases for my Service Class. Below is my code in controller:
TuneController
def list = {
}
def listData= {
playerId="6600AE"
def tuneInstanceList = new ArrayList<Tune>()
tuneInstanceList = tuneService.calculateId(String playerId)
def editResult = [total: tuneInstanceList.size(), items: tuneInstanceList]
render editResult as JSON;
}
Below is my code in TuneService: The below
method is called from listData action. ListData is mentioned
in my js file test.js
List<Tune> calculateId(String playerId) {
try{
//read the sql file
String playerSql = grailsApplication.mainContext.getResource('classpath:' + Constants.PLAYER_FILE).inputStream.text
def sql = new groovy.sql.Sql(dataSource)
def params = [playerId:playerId]
def tuneInstanceList = new ArrayList<Tune>()
def results = sql.rows(playerSql, params)
tuneInstanceList = results.each {
def tune = new Tune()
tune.setPlayerId it.player_id
tuneInstanceList.add tune
}
return tuneInstanceList
}catch (Exception ex) {
log.error ex.message, ex
throw ex
}
//finally {
//sql.close()
//}
}
PLAYER_FILE.sql has the below data. This file is present in grails-app/sql/PLAYER_FILE.sql
select player_Id from tunes where player_Id=:playerId
Test.js:
Ext.onReady(function(){
// create the Data Store
var ds = new Ext.data.Store({
autoLoad: true,
proxy: new Ext.data.HttpProxy({
url: 'http://localhost:8080/music/tune/listData'}),
reader: new Ext.data.JsonReader({
results: 'total',
root:'items',
id:'id'
},
[
{name: 'playerId' }
]
)
});
var cm = new Ext.grid.ColumnModel([
{header: "Player Id", width: 120, dataIndex: 'playerId' },
]);
cm.defaultSortable = true;
// create the grid
var grid = new Ext.grid.GridPanel({
ds: ds,
cm: cm,
renderTo:'grid-example',
width:540,
height:200
}); });
Below is the test that I wrote for my service class. Here I am getting the missing prperty exception. I believe this is for the
line "def sql = new groovy.sql.Sql(dataSource)". This is what is mentioned in the exceptions. Its reg. this sql. Here in my test, I have to mention the datasource or mock the datasource. I am not too sure though.
My test case is below:
void testReturnList() {
TuneService tuneService = new TuneService()
List tuneList = tuneService.calculateId()
assertTrue(tuneList.size()>0)
}
groovy.lang.MissingPropertyException: No such property: sql for class: pride.TuneService
Possible solutions: log
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:49)
at org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.getProperty(GetEffectivePogoPropertySite.java:86)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:241)
at pride.TuneService.calculateId(TuneService.groovy:67)
at pride.TuneService$calculateId.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
at pride.TuneServiceTests.testReturnList(TuneServiceTests.groovy:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
EDITED: Below is the error that I get after commenting sql.close()
java.lang.NullPointerException: Cannot get property 'mainContext' on null object
at org.codehaus.groovy.runtime.NullObject.getProperty(NullObject.java:56)
at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:156)
at org.codehaus.groovy.runtime.callsite.NullCallSite.getProperty (NullCallSite.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty (AbstractCallSite.java:237)
at pride.TuneService.calculateId(TuneService.groovy:37)
at pride.TuneService$calculateId.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
at pride.TuneServiceTests.testReturnList(TuneServiceTests.groovy:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
How do I go about writing this test case. Thoughts?
I don't think you've given us the right code to help you debug this error. If you examine the stack trace more closely, you'll see where the "missing property" is:
at pride.RecoveryService.calculateImpact(RecoveryService.groovy:67)
Have a look at that line. It's likely that you're referring to a property called sql that hasn't been defined for the method/closure/class.
Edit:
After your update, I see at least one problem:
String sql = grailsApplication.mainContext.getResource('classpath:' + Constants.PLAYER_FILE).inputStream.text
def sql = new groovy.sql.Sql(dataSource)
You're defining sql twice here as different types. I only point that out because your stack trace seems to be related to that variable.
Can you point out which line is line in TuneService.groovy is line 67?
Related
I am running a unit test using PowerMockito to perform a query using Vert.x's CassandraClient and I see ClassCastException.
Similar code works when performing updates.
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(VertxUnitRunner.class)
#PowerMockIgnore("javax.management.*")
#PrepareForTest({ CassandraClient.class, ResultSet.class, Row.class })
class TestCassandraClient {
#Mock
private AsyncResult<List<Row>> asyncListRow;
#Mock
private List<Row> listRow;
#Test
public void testQueryKeyspaces(TestContext context) {
Mockito.when(asyncListRow.succeeded()).thenReturn(true);
Mockito.when(asyncListRow.result()).thenReturn(listRow);
Mockito.when(listRow.size()).thenReturn(0);
Mockito.doAnswer(new Answer<AsyncResult<List<Row>>>() {
#SuppressWarnings("unchecked")
#Override
public AsyncResult<List<Row>> answer(InvocationOnMock invocation) throws Throwable {
((Handler<AsyncResult<List<Row>>>) invocation.getArgument(1)).handle(asyncListRow);
return asyncListRow;
}
}).when(client).executeWithFullFetch(Mockito.anyString(), Mockito.any());
Async async = context.async(1);
try {
(new Operation()).queryAll(client, "SELECT * FROM system_schema.keyspaces")
.setHandler(ar -> {
if (ar.succeeded()) {
async.complete();
} else {
context.fail("Failed to perform operation");
}
});
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
context.verify(v -> {
Assert.fail(e.getMessage());
});
async.complete();
}
}
}
The method "queryAll" is as below:
Class Operation {
public Future<OperationResult> queryAll(#NonNull final CassandraClient client, #NonNull final String query) {
Objects.requireNonNull(client, "CassandraClient cannot be null");
Objects.requireNonNull(query, "Update query cannot be null");
Future<OperationResult> future = Future.future();
try {
client.executeWithFullFetch(query, rh -> {
OperationResult resultObj = new OperationResult();
if (rh.succeeded()) {
resultObj.setSuccess(true);
List<Row> rows = rh.result();
if (rows != null && rows.size() > 0) {
Row row = rows.get(0);
ColumnDefinitions colDefs = row.getColumnDefinitions();
resultObj.setColumnDefinitions(toJsonArray(colDefs));
}
resultObj.setData(toJsonArray(rows));
} else {
resultObj.setSuccess(false);
resultObj.setException(rh.cause().getMessage());
}
future.complete(resultObj);
});
} catch (Exception e) {
String msg = String.format("Problem invoking query: %s. Error: %s", query, e.getMessage());
LOGGER.error(msg, e);
OperationResult resultObj = new OperationResult();
resultObj.setSuccess(false);
resultObj.setException(msg);
future.complete(resultObj);
}
return future;
}
}
Note that I have added a mock instruction
to return zero rows
Mockito.when(listRow.size()).thenReturn(0);
So, In the first line you see the response is returning a list of zero rows, but next I see an error as below.
05:21:41.015 [vert.x-eventloop-thread-0] DEBUG c.b.t.p.c.api.beans.OperationResult - JSON representation: {"column-definitions":null,"rows":[],"success":true,"exception":null}
05:21:41.015 [vert.x-eventloop-thread-0] ERROR c.b.t.p.c.api.operation.Operation - Problem invoking query: SELECT * FROM system_schema.keyspaces. Error: io.vertx.core.AsyncResult$MockitoMock$1728182793 cannot be cast to io.vertx.cassandra.CassandraClient
java.lang.ClassCastException: io.vertx.core.AsyncResult$MockitoMock$1728182793 cannot be cast to io.vertx.cassandra.CassandraClient
at io.vertx.cassandra.CassandraClient$MockitoMock$873315432.executeWithFullFetch(Unknown Source)
at com.bmc.tso.persistence.client.api.operation.Operation.queryAll(Operation.java:195)
at com.bmc.tso.persistence.client.api.operation.KeyspaceOperationUnitTest.testQueryKeyspaces(KeyspaceOperationUnitTest.java:372)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at io.vertx.ext.unit.junit.VertxUnitRunner.invokeTestMethod(VertxUnitRunner.java:95)
at io.vertx.ext.unit.junit.VertxUnitRunner.lambda$invokeExplosively$0(VertxUnitRunner.java:114)
at io.vertx.ext.unit.impl.TestContextImpl.run(TestContextImpl.java:90)
at io.vertx.ext.unit.junit.VertxUnitRunner.lambda$invokeExplosively$1(VertxUnitRunner.java:127)
at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:320)
at io.vertx.core.impl.EventLoopContext.lambda$executeAsync$0(EventLoopContext.java:38)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
05:21:
Can someone help me figure out why my kotlin variable that i mocked and named "repo" is still executing a method im telling mockito to mock ? let me show you what i mean:
i have a simple usecase class that looks like this:
class WeatherDetailsPresenter #Inject constructor(var getCurrentWeatherWithForecastUsecase: GetCurrentWithForcastedWeatherUsecase) : BaseMvpPresenter<WeatherDetailsView>() {
fun presentCurrentAndForcastedWeather(country: String?) {
with{getCurrentWeatherWithForecastUsecase) {
this.countyName = country
execute(object : DefaultSubscriber<Pair<CurrentWeatherModel, ForecastedWeatherModel>>() {
override fun onSubscribe(d: Disposable) {
super.onSubscribe(d)
showLoading(true)
}
override fun onNext(t: Pair<CurrentWeatherModel, ForecastedWeatherModel>) {
super.onNext(t)
view?.showCurrentWeather(t.first)
}
override fun onComplete() {
super.onComplete()
showLoading(false)
}
})
}
}
}
all it does is you pass it a country name and it gets the average weather for that country and also 7 day forecast. no big deal. it puts it all together in a pair and updates the view (MVP). it fetches the data from another class called a WeatherDataRepository who's implementation is not import as long as it returns data we dont care.
let me show you what the getCurrentWeatherWithForecastUsecase class actgually looks like:
class GetCurrentWithForcastedWeatherUsecase #Inject constructor(var weatherRepo: WeatherDataRepository) : BaseUseCase() {
var countyName: String? = null
override fun buildUseCaseObservable(): Observable<Pair<CurrentWeatherModel, ForecastedWeatherModel>> {
return weatherRepo.fetchCurrentWeatherWith7dayForcast(countyName.toString())
}
}
//see its easy it just takes a weatherRepository and asked it to fetch the results. i send that back to the caller who will display it.
now that you know what this simple method does let me show you what i am trying to test. I wish to simply test that the currentweather was shown. so really in the end i want to test that view?.showCurrentWeather(t.first) was called.
Here is my junit test case:
class WeatherDetailsPresenterTest {
lateinit var usecase: GetCurrentWithForcastedWeatherUsecase
#Mock
lateinit var repo: WeatherDataRepository
#Mock
lateinit var view: WeatherDetailsView
lateinit var presenter: WeatherDetailsPresenter
#Before
fun setUp() {
MockitoAnnotations.initMocks(this)
usecase = GetCurrentWithForcastedWeatherUsecase(repo)
presenter = WeatherDetailsPresenter(usecase)
}
#Test
fun testCurrentWeatherScreenAppears() {
//arrange
//WHY IS THIS MOCK NOT WORKING ??
Mockito.`when`(repo.fetchCurrentWeatherWith7dayForcast(anyString())).thenReturn(Observable.just(Pair<CurrentWeatherModel, ForecastedWeatherModel>(ArgumentMatchers.any(CurrentWeatherModel::class.java),ArgumentMatchers.any(ForecastedWeatherModel::class.java))))
//act
val testSubscriber = TestObserver<Pair<CurrentWeatherModel, ForecastedWeatherModel>>()
usecase.execute(testSubscriber)
//assert
testSubscriber.assertNoErrors()
testSubscriber.assertSubscribed()
testSubscriber.assertValue(Pair(ArgumentMatchers.any(), ArgumentMatchers.any()))
testSubscriber.assertComplete()
Mockito.verify(view,times(1)).showCurrentWeather(any())
}
}
The unit tests compiles and runs. the issue is the repository call is actually calling fetchCurrentWeatherWith7dayForcast instead of just returning the mock response.
here is the error when i run the test cases (failure error):
java.lang.NullPointerException
at me.org.myweatherapp.data.repositories.WeatherDataRepository.fetchCurrentWeatherWith7dayForcast(WeatherDataRepository.kt:17)
at me.org.myweatherapp.presentation.view.mvp.mainScreen.fragments.weatherdetails.WeatherDetailsPresenterTest.testCurrentWeatherScreenAppears(WeatherDetailsPresenterTest.kt:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
you should not need to see the repository code but i'll show it anyway:
class WeatherDataRepository #Inject constructor(val retrofit: Retrofit){
//THIS SHOULD NEVER BE CALLED, SINCE IM MOCKING IT, BUT ITS CALLED, WHY??
fun fetchCurrentWeatherWith7dayForcast(countyName: String): Observable<Pair<CurrentWeatherModel, ForecastedWeatherModel>> {
val weatherApiService = retrofit.create(WeatherApi::class.java)
return weatherApiService.getCurrentWeather(countyName)
.zipWith<ForecastedWeatherModel,Pair<CurrentWeatherModel, ForecastedWeatherModel>>(weatherApiService.getForecastedWeather(countyName)
.map{model-> model.forecast?.forecastday?.forEach { it?.dayName= getDay(it?.date.toString())}; model }
, BiFunction { t1, t2 -> Pair(t1,t2) })
}}
i am already annotating the repo to be mocked and then in the setup i initialized all mocks, so the only thing i can think of is im not using the Mockito.when command the right away ? any help appreciated.
UPDATE:
HERE IS THE ENTIRE STACK TRACE OF THE FAILURE:
"/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java" -ea -Didea.test.cyclic.buffer.size=1048576 -Didea.launcher.port=57805 "-Didea.launcher.bin.path=/Applications/Android Studio.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath "/Applications/Android Studio.app/Contents/lib/idea_rt.jar:/Applications/Android Studio.app/Contents/plugins/junit/lib/junit-rt.jar:/Applications/Android Studio.app/Contents/plugins/junit/lib/junit5-rt.jar:/Users/me/Library/Android/sdk/platforms/android-27/data/res:/Users/me/Documents/mystuff/weatherappdemo/app/build/intermediates/classes/prod/debug:/Users/me/Library/Android/sdk/extras/m2repository/com/android/support/constraint/constraint-layout-solver/1.0.2/constraint-layout-solver-1.0.2.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/support-v4-27.1.1.aar/8c528b77506492992ca9cefd2fbe3fc1/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.2.21/88bfff5aa470143a83b0bc5ec00c0be8cabd7cad/kotlin-stdlib-jdk7-1.2.21.jar:/Users/me/.gradle/caches/modules-2/files-2.1/commons-cli/commons-cli/1.2/2bf96b7aa8b611c177d329452af1dc933e14501c/commons-cli-1.2.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-reflect/1.2.41/e4d6728a4fa55dbfb510aeea25c072c7c51d94/kotlin-reflect-1.2.41.jar:/Users/me/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/common-java8/1.0.0/a7458929c2f84a8a59b6b4da631a36f07091cf79/common-java8-1.0.0.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/support-media-compat-27.1.1.aar/8c1ab73749282027c9894ed4f6387856/res:/Users/me/.gradle/caches/transforms-1/files-1.1/support-media-compat-27.1.1.aar/8c1ab73749282027c9894ed4f6387856/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.bouncycastle/bcprov-jdk15on/1.50/be504b4901d75cbe129a178f5830e6c358ec214c/bcprov-jdk15on-1.50.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/stetho-1.5.0.aar/f176def4c2ceb952e3ab306a7d56241a/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/rules-1.0.1.aar/88459f9e0846eb9599bad2e0efbab6bb/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-auth-base-license-11.8.0.aar/1f271bdf7747c7247ce3e2d7b7a8ff8e/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-basement-license-11.8.0.aar/9ae67be5ece95255b9bcca7d0378d2b4/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-iid-11.8.0.aar/951a9ce1737846087ee53aaecfb671c0/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/support-fragment-27.1.1.aar/227f5a73c4224f35e666b27741d51529/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.squareup.retrofit2/retrofit/2.3.0/bcacde6a8ccedcc56c127403d26b76072fe6214d/retrofit-2.3.0.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/runtime-1.1.0.aar/506f9955d304b32a4564c4b84422fea4/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/design-27.1.1.aar/4f85b6a28d4b1cf224a5e6cb1d4dbc66/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/design-27.1.1.aar/4f85b6a28d4b1cf224a5e6cb1d4dbc66/res:/Users/me/.gradle/caches/transforms-1/files-1.1/runtime-1.0.0.aar/7af827a5af0341c7eceb2a9ffa27a39e/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/multidex-instrumentation-1.0.2.aar/d67f47874da4e87ad02796a65dc73f61/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-config-11.8.0.aar/bc62621a53fdb88540784b9828b13fde/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/appcompat-v7-27.1.1.aar/23e568de9f4f0daff9b5d756af53aa07/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/appcompat-v7-27.1.1.aar/23e568de9f4f0daff9b5d756af53aa07/res:/Users/me/.gradle/caches/modules-2/files-2.1/org.greenrobot/eventbus/3.0.0/ddd99896e9569eaababbe81b35d80e1b91c4ad85/eventbus-3.0.0.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp/3.8.0/5a11f020cce2d11eb71ba916700600e18c4547e7/okhttp-3.8.0.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-analytics-impl-11.8.0.aar/5b4765afdec874f91c04f5abe56e5275/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/android.arch.persistence.room/common/1.0.0/1cbd3ddc566125293b13af5c0a65bc015476e83c/common-1.0.0.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/runtime-1.1.0.aar/1fb10be0704f03034b6aa2314ccf3e4d/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/transition-27.1.1.aar/91b8eaec16a28ef6b3781544873a983d/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/transition-27.1.1.aar/91b8eaec16a28ef6b3781544873a983d/res:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-auth-base-11.8.0.aar/882aae6015201ef880d7ddb46766a289/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/butterknife-8.8.1.aar/cf0409e6eb4d8f95c289b322c09c7470/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/fbcore-1.3.0.aar/881eb80147e1a600eb4fdd7ca2ca248e/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-common-11.8.0.aar/7840ba4061070f9ac09a6db65e355818/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-analytics-impl-license-11.8.0.aar/a56e270bd3ae1a384d54e6bd9a48d02d/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/uiautomator-v18-2.1.0.aar/9b94013d0aeaac82611731b234cecc7b/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/support-compat-27.1.1.aar/8da86b1dff1f0160efbb1b9cd1b03a26/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/support-compat-27.1.1.aar/8da86b1dff1f0160efbb1b9cd1b03a26/res:/Users/me/.gradle/caches/transforms-1/files-1.1/espresso-contrib-3.0.1.aar/775bf13abb0c730effcf8406c262c9f3/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/viewmodel-1.1.0.aar/1decb5c20af306b59139842edceb0bf7/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.reactivestreams/reactive-streams/1.0.0/14b8c877d98005ba3941c9257cfe09f6ed0e0d74/reactive-streams-1.0.0.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-core-11.8.0.aar/40ccc15d85cb93820d69a9a52ee41860/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.jakewharton/butterknife-annotations/8.8.1/bc373fb6bc7bca3035041b924f158fd2b946ee8d/butterknife-annotations-8.8.1.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions-runtime/1.2.41/c1fd16a8b0be2f6c95dd43e1560d5b86ff742fdc/kotlin-android-extensions-runtime-1.2.41.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/spots-dialog-0.7.aar/d5614913769f6b38243111c590a8482f/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/spots-dialog-0.7.aar/d5614913769f6b38243111c590a8482f/res:/Users/me/.gradle/caches/transforms-1/files-1.1/support-vector-drawable-27.1.1.aar/5eb343d801e7f29a5d223861abe3b6fc/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/stetho-okhttp3-1.5.0.aar/519dbbb66efddad4a4bfae9c6e76718d/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-iid-license-11.8.0.aar/423297131a354e0bfbd7103a38722964/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.github.ihsanbal/LoggingInterceptor/2.0.2/e0230eb518409058f04f1be8e356d9dfd9d7126b/LoggingInterceptor-2.0.2.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/support-core-utils-27.1.1.aar/10757417e97a4e5d394b007d55ed39df/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-basement-11.8.0.aar/96b45c45c9e7d0359214ab8878e5b137/res:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-basement-11.8.0.aar/96b45c45c9e7d0359214ab8878e5b137/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.2.41/7e34f009642702250bccd9e5255866f408962a05/kotlin-stdlib-1.2.41.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/2.0.1/516c03b21d50a644d538de0f0369c620989cd8f0/jsr305-2.0.1.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/imagepipeline-base-1.3.0.aar/a7e27f7f6f4d580103459e14d4d91132/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-base-license-11.8.0.aar/0e66bd26413f298ad4b21d093883f138/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/core-ktx-0.1.aar/b15ebaf7972ab87fc408b81f8cd9b7f8/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.squareup.retrofit2/adapter-rxjava2/2.3.0/f436637f9500ab5b8bc32afe556373180894b4a5/adapter-rxjava2-2.3.0.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger/2.9/75a739e59d7ede2f7f425f369955bdd1c2ac122b/dagger-2.9.jar:/Users/me/.gradle/caches/modules-2/files-2.1/net.bytebuddy/byte-buddy/1.6.14/871c3e49dc6183d0d361601c2f1d11abb1a6b48c/byte-buddy-1.6.14.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/imagepipeline-1.3.0.aar/f7d55bb54a7fcb0dc52ca620f3cb3390/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/rxbinding-2.0.0.aar/71b2449f24db0bbe295118e38c3b099c/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/common/1.1.0/edf3f7bfb84a7521d0599efa3b0113a0ee90f85/common-1.1.0.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/drawee-1.3.0.aar/0d2fd7b15bc817f241bd45a7af724235/res:/Users/me/.gradle/caches/transforms-1/files-1.1/drawee-1.3.0.aar/0d2fd7b15bc817f241bd45a7af724235/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.objenesis/objenesis/2.5/612ecb799912ccf77cba9b3ed8c813da086076e9/objenesis-2.5.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.google.code.gson/gson/2.7/751f548c85fa49f330cecbb1875893f971b33c4e/gson-2.7.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jre7/1.2.41/9e7a6f582de73d9cdc6c56ef4e23604a0ee55768/kotlin-stdlib-jre7-1.2.41.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/logging-interceptor/3.8.0/f765f004f3e201bd6ad0904266e605d7fb776d5/logging-interceptor-3.8.0.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/recyclerview-v7-27.1.1.aar/5c32c514912225f8996a860cdae759cb/res:/Users/me/.gradle/caches/transforms-1/files-1.1/recyclerview-v7-27.1.1.aar/5c32c514912225f8996a860cdae759cb/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/multidex-1.0.2.aar/3d385f486b764139c13b624fee0b32c0/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/support-core-ui-27.1.1.aar/10a6e827fb24388f3d393ee95b15305c/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/support-core-ui-27.1.1.aar/10a6e827fb24388f3d393ee95b15305c/res:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-tasks-license-11.8.0.aar/f8cc3f0ba924aff3c7d5cc7c9c56f7e9/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/idling-concurrent-3.0.1.aar/bf368765eb5955d1a89d234f6c5669ee/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/rxjava2-1.0.0.aar/406d1a35f2fb9c28ac1c637df15d49db/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.squareup.retrofit2/converter-gson/2.3.0/9e09011e9767bb76b5e27c9b8223476b93b14631/converter-gson-2.3.0.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-messaging-license-11.8.0.aar/0c9522887d98bb37f93e8694bc9cab09/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-config-license-11.8.0.aar/6602b35b3e55aebb6ac4665e9872b5fc/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/io.reactivex.rxjava2/rxjava/2.1.1/99895d4dc6d79efbb74360f13c556d95533ad8f8/rxjava-2.1.1.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-auth-api-phone-license-11.8.0.aar/f3df85960ad3eeb19f7be4ce902b978a/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/db-framework-1.0.0.aar/796c04fce9221c438948f9c68e14c88c/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/viewstate-2.0.1.aar/bf016c65c3e0c7dcafda5281f41b4e81/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/db-1.0.0.aar/81d8f63860272b7c43a6709748e52ee9/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/io.reactivex.rxjava2/rxjava/2.1.7/8c6d3f76a0b8ed49e9d49a5af9c80c5fc2091677/rxjava-2.1.7.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-messaging-11.8.0.aar/fbcba383734b49591176a7772066d087/res:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-messaging-11.8.0.aar/fbcba383734b49591176a7772066d087/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-common-license-11.8.0.aar/a853cc000b4a9e97a1e8cb8510bbde3a/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-auth-11.8.0.aar/e8a403bb2bc41b0978151644434be336/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/runner-1.0.1.aar/bc61594971ebf029997add3d9e064acb/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/timber-4.5.1.aar/ed168ba0862d519a47bca16bf4dac2df/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.android.support/support-annotations/27.1.1/39ded76b5e1ce1c5b2688e1d25cdc20ecee32007/support-annotations-27.1.1.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-27.1.1.aar/e91ef01a13292102a7a45e6e1080e1fb/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-analytics-license-11.8.0.aar/6b229f59f2b7a192f74a9c7d5a33dfe2/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-auth-api-phone-11.8.0.aar/a76aa8978d4a42b84287b4c62555d7a0/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-analytics-11.8.0.aar/9dfc8e29830fdadd2e7d25b1baa19671/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.parse.bolts/bolts-tasks/1.4.0/d85884acf6810a3bbbecb587f239005cbc846dc4/bolts-tasks-1.4.0.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.squareup.okio/okio/1.13.0/a9283170b7305c8d92d25aff02a6ab7e45d06cbe/okio-1.13.0.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/fresco-1.3.0.aar/db4a2dd4f4c2cab75bf3453e6639ed58/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/rx2-idler-0.9.0.aar/2592289841865b391355f5d4fc368251/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/espresso-intents-3.0.1.aar/eb5beafb4e6532e880eb8af7a315b9f6/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.reactivestreams/reactive-streams/1.0.1/1b1c911686eb40179219466e6a59b634b9d7a748/reactive-streams-1.0.1.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/mvp-2.0.1.aar/f0614328bd1e1100af13886a9dcde777/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/mvp-2.0.1.aar/f0614328bd1e1100af13886a9dcde777/res:/Users/me/.gradle/caches/transforms-1/files-1.1/espresso-core-3.0.1.aar/3d7b614004a6eaa78227a35fd3cee256/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/espresso-web-3.0.1.aar/cf8ebc9ea102e614f709045983fb32a7/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/rxandroid-2.0.1.aar/5516ddab631416f22f025eb065849949/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.0.2.aar/3eb445c5139d11809f5142c08a3b669a/res:/Users/me/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.0.2.aar/3eb445c5139d11809f5142c08a3b669a/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/junit/junit/4.12/2973d150c0dc1fefe998f834810d68f278ea58ec/junit-4.12.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-base-11.8.0.aar/6022e015ee3a8def24bc31049a72d6b5/res:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-base-11.8.0.aar/6022e015ee3a8def24bc31049a72d6b5/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/espresso-idling-resource-3.0.1.aar/12c9fd22796fd8b15ccaf8884ae23c20/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.2.21/86407aed2dc197bd5f61d16e759c4ff43678732a/kotlin-stdlib-jdk8-1.2.21.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.rubylichtenstein/rxtest/1.0.7/43a4d1a2b4dcc14c669f4be81680a4e4b7d3dd1e/rxtest-1.0.7.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.squareup.picasso/picasso/2.5.2/7446d06ec8d4f7ffcc53f1da37c95f200dcb9387/picasso-2.5.2.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/livedata-core-1.1.0.aar/518c06f36c54349dedb9b4d7d98fdde5/jars/classes.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-tasks-11.8.0.aar/c516e10968cea0d1c7a34bf5a433c591/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/mockwebserver/3.8.0/6bcc6566897ffae93c62e53ff8e8e71af18d7593/mockwebserver-3.8.0.jar:/Users/me/.gradle/caches/modules-2/files-2.1/com.hannesdorfmann.mosby/mvp-common/2.0.1/d75c9c5577143f3cf3fd63f61526a551f910b56f/mvp-common-2.0.1.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-auth-11.8.0.aar/860f44f092aa569d6e12cc2a8b2f1f16/res:/Users/me/.gradle/caches/transforms-1/files-1.1/play-services-auth-11.8.0.aar/860f44f092aa569d6e12cc2a8b2f1f16/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/android.arch.core/common/1.1.0/8007981f7d7540d89cd18471b8e5dcd2b4f99167/common-1.1.0.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/timberkt-1.3.0.aar/3061f0b036f5136e670a5c16d103a232/jars/classes.jar:/Users/me/.gradle/caches/modules-2/files-2.1/net.bytebuddy/byte-buddy-agent/1.6.14/ba1e5ba3a84fb2fbf2f4de9138df19665eec4d59/byte-buddy-agent-1.6.14.jar:/Users/me/.gradle/caches/modules-2/files-2.1/org.mockito/mockito-core/2.8.9/1afb35b2d77d40567756c379e54c18da3574a96e/mockito-core-2.8.9.jar:/Users/me/.gradle/caches/transforms-1/files-1.1/firebase-auth-license-11.8.0.aar/c11a9a832d941e454c91804c30c3b8e5/jars/classes.jar:/Users/me/Documents/mystuff/weatherappdemo/app/build/intermediates/sourceFolderJavaResources/test/prod/debug:/Users/me/Documents/mystuff/weatherappdemo/app/build/tmp/kotlin-classes/prodDebugUnitTest:/Users/me/Documents/mystuff/weatherappdemo/app/build/tmp/kapt3/classes/prodDebugUnitTest:/Users/me/Documents/mystuff/weatherappdemo/app/build/intermediates/sourceFolderJavaResources/prod/debug:/Users/me/Documents/mystuff/weatherappdemo/app/build/tmp/kapt3/classes/prodDebug:/Users/me/Documents/mystuff/weatherappdemo/app/build/tmp/kotlin-classes/prodDebug:/Users/me/Documents/mystuff/weatherappdemo/app/build/generated/mockable-android-27.v3.jar" com.intellij.rt.execution.application.AppMainV2 com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 me.org.weatherapp.presentation.view.mvp.mainScreen.fragments.weatherdetails.WeatherDetailsPresenterTest
java.lang.NullPointerException
at me.org.weatherapp.data.repositories.WeatherDataRepository.fetchCurrentWeatherWith7dayForcast(WeatherDataRepository.kt:17)
at me.org.weatherapp.presentation.view.mvp.mainScreen.fragments.weatherdetails.WeatherDetailsPresenterTest.testCurrentWeatherScreenAppears(WeatherDetailsPresenterTest.kt:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:78)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:84)
at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:161)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:131)
I finally saw my issue. i was making it too complicated. First the presenter should subscribe to the observable so my baseUseCase should look like this instead:
public abstract class BaseUseCase {
protected abstract Observable buildUseCaseObservable();
#SuppressWarnings("unchecked")
public Observable retrieveUseCaseObservable(){
return this.buildUseCaseObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}
then the actual test case simply mocks the usecase and view and tests the presenter and it all seems work now:
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.BDDMockito
import org.mockito.BDDMockito.given
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.mockito.runners.MockitoJUnitRunner
#RunWith(MockitoJUnitRunner::class)
class WeatherDetailsPresenterTest {
#Mock
lateinit var usecase: GetCurrentWithForcastedWeatherUsecase
#Mock
lateinit var view: WeatherDetailsView
lateinit var presenter: WeatherDetailsPresenter
#Before
fun setUp() {
MockitoAnnotations.initMocks(this)
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
presenter = WeatherDetailsPresenter(usecase)
presenter.attachView(view)
}
#Test
fun testCurrentWeatherScreenAppears() {
//arrange
given(usecase.retrieveUseCaseObservable()).willReturn(Observable.just(Pair(CurrentWeatherModel(), ForecastedWeatherModel())))
//act
presenter.presentCurrentAndForcastedWeather("canada")
//assert
BDDMockito.verify(view, BDDMockito.times(1)).showCurrentWeather(any(CurrentWeatherModel::class.java)?:CurrentWeatherModel())
}
}
the elvis operation is to satisfy kotlin
when we make the presenter call note that now i am subscribing from within the presenter:
fun presentCurrentAndForcastedWeather(country: String?) {
getCurrentWeatherWithForecastUsecase.takeUnless { country?.isBlank() == true }?.apply {
this.countyName = country
retrieveUseCaseObservable().subscribe(object : DefaultSubscriber<Pair<CurrentWeatherModel, ForecastedWeatherModel>>() {
override fun onSubscribe(d: Disposable) {
super.onSubscribe(d)
showLoading(true)
}
override fun onNext(t: Pair<CurrentWeatherModel, ForecastedWeatherModel>) {
super.onNext(t)
view?.showCurrentWeather(t.first)
view?.showForcastWeather(t.second)
}
override fun onError(e: Throwable) {
super.onError(e)
showError { this#WeatherDetailsPresenter.presentCurrentAndForcastedWeather(country) }
}
override fun onComplete() {
super.onComplete()
showLoading(false)
}
})
} ?: run { view?.showCountryUnavailable() }
}
i also added RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
to tell the rxJava system to run on the current thread, since everythings mocked anyway.
I have a service which I'd like to test which is as follows:
class MyService {
def dataSource
def method1(id) {
Sql sql = Sql.newInstance(dataSource)
def query = "select * from some_table where id = ?"
sql.eachRow(query, [id]) { row ->
// do stuff with row
}
}
}
I'm trying to test this with MockFor
class MyServiceTest extends GroovyTestCase {
#Test
void testMethod1() {
def mockResults = [
[ id:1, name:"foo", ...]
]
def mockSql = new MockFor(Sql.class)
mockSql.demand.newInstance { mockSql }
mockSql.demand.eachRow { query, params, closure ->
// run the closure over the mock array
mockResults.each(closure)
}
mockSql.use {
MyService myService = new MyService()
myService.method1(1)
}
}
}
But I get the following exception:
junit.framework.AssertionFailedError: No call to 'newInstance' expected at this point. Still 1 call(s) to 'eachRow' expected.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:77)
at org.codehaus.groovy.reflection.CachedConstructor.doConstructorInvoke(CachedConstructor.java:71)
at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrap.callConstructor(ConstructorSite.java:81)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:57)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:182)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:190)
at groovy.mock.interceptor.StrictExpectation.match(StrictExpectation.groovy:56)
at groovy.mock.interceptor.StrictExpectation$match.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at groovy.mock.interceptor.MockInterceptor.beforeInvoke(MockInterceptor.groovy:31)
at groovy.mock.interceptor.MockProxyMetaClass.invokeStaticMethod(MockProxyMetaClass.java:98)
at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:50)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at com.bnpparibas.client1st.service.MetricsService.getClientDocumentsStatistic(MetricsService.groovy:483)
at com.bnpparibas.client1st.service.MetricsService$getClientDocumentsStatistic.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:128)
at MyServiceTest$_testMethod1_closure
I think you have incorrect mock for newInstance method. Should be:
mockSql.demand.newInstance { def datasource->
return mockSql
}
The same for eachRow method. Add def before every closure argument.
I am trying to build a RESTFUL Web Service however I am getting an error under is my code:
jsp
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<style>
<%# include file="../css/forms.css" %>
</style>
<script type="text/javascript">
<%# include file="../js/off_reg.js"%>
$(document).ready(function(){
$('#userName').blur(function(evt){
CheckAvailability();
});
});
function CheckAvailability(){
$.ajax( {
type:'GET', //Could be 'get' depending on your needs
url:'validateUserName.htm',
data:{userName:$('#userName').val()},
dataType: 'json',
success:function(data) {
alert(data);
}
});
}
</script>
DAO
public boolean OfficerExist(String userName){
try{
logger.debug("About to check if officers existing");
String sql = "SELECT userName FROM crimetrack.tblofficers WHERE userName = ?";
logger.info("at this point 1");
//String dbUserName = (String)results.get("userName");
String dbUserName = (String)getJdbcTemplate().queryForObject(sql, new Object[]{userName},String.class);
logger.info("after JdbcTemplate");
if (dbUserName.equals(userName)) {
logger.info("User Name Exists");
return true;
}else{
logger.info("User Name Does NOT Exists");
return false;
}
}catch(Exception e){
logger.info(e.getMessage());
return false;
}
}
FireBug Console Error:
GET http://localhost:8084/crimeTrack/validateUserName.htm?userName=hello
500 Internal Server Error
70ms
jquery.min.js (line 2)
"NetworkError: 500 Internal Server Error - http://localhost:8084/crimeTrack /validateUserName.htm?userName=hello"
TomCat Error Log:
com.crimetrack.web.OfficerRegistrationController.validateUserName(java.lang.String,com.crimetrack.business.Officers,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws java.lang.Exception
306270 [http-8084-1] DEBUG com.crimetrack.web.OfficerRegistrationController - Inside Controller validateUserName
306270 [http-8084-1] DEBUG com.crimetrack.web.OfficerRegistrationController - The user name that came in is hello
306270 [http-8084-1] INFO com.crimetrack.service.ValidateUserNameManager - Inside Do UserNameExist
306270 [http-8084-1] DEBUG com.crimetrack.jdbc.JdbcOfficersDAO - About to check if officers existing
306270 [http-8084-1] INFO com.crimetrack.jdbc.JdbcOfficersDAO - User Name Found 1
306270 [http-8084-1] INFO com.crimetrack.jdbc.JdbcOfficersDAO - User Name Found 2
306270 [http-8084-1] DEBUG org.springframework.jdbc.core.JdbcTemplate - Executing prepared SQL query
306270 [http-8084-1] DEBUG org.springframework.jdbc.core.JdbcTemplate - Executing prepared SQL statement [SELECT userName FROM crimetrack.tblofficers WHERE userName = ?]
306270 [http-8084-1] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
306285 [http-8084-1] DEBUG org.springframework.jdbc.core.StatementCreatorUtils - Setting SQL statement parameter value: column index 1, parameter value [hello], value class [java.lang.String], SQL type unknown
306289 [http-8084-1] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
306289 [http-8084-1] INFO com.crimetrack.jdbc.JdbcOfficersDAO - Incorrect result size: expected 1, actual 0
306289 [http-8084-1] DEBUG org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver - Resolving exception from handler [com.crimetrack.web.OfficerRegistrationController#a32cdd]: java.lang.IllegalArgumentException: Invalid handler method return value: false
306289 [http-8084-1] DEBUG org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver - Resolving exception from handler [com.crimetrack.web.OfficerRegistrationController#a32cdd]: java.lang.IllegalArgumentException: Invalid handler method return value: false
306289 [http-8084-1] DEBUG org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - Resolving exception from handler [com.crimetrack.web.OfficerRegistrationController#a32cdd]: java.lang.IllegalArgumentException: Invalid handler method return value: false
306290 [http-8084-1] DEBUG org.springframework.web.servlet.DispatcherServlet - Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade#1cbab62
306290 [http-8084-1] DEBUG org.springframework.web.servlet.DispatcherServlet - Could not complete request
java.lang.IllegalArgumentException: Invalid handler method return value: false
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.getModelAndView(AnnotationMethodHandlerAdapter.java:971)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:438)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Unknown Source)
306290 [http-8084-1] DEBUG org.springframework.web.context.support.XmlWebApplicationContext - Publishing event in WebApplicationContext for namespace 'crimetrack-servlet': ServletRequestHandledEvent: url=[/crimeTrack/validateUserName.htm]; client=[127.0.0.1]; method=[GET]; servlet=[crimetrack]; session=[null]; user=[null]; time=[28ms]; status=[failed: java.lang.IllegalArgumentException: Invalid handler method return value: false]
306290 [http-8084-1] DEBUG org.springframework.web.context.support.XmlWebApplicationContext - Publishing event in Root WebApplicationContext: ServletRequestHandledEvent: url=[/crimeTrack/validateUserName.htm]; client=[127.0.0.1]; method=[GET]; servlet=[crimetrack]; session=[null]; user=[null]; time=[28ms]; status=[failed: java.lang.IllegalArgumentException: Invalid handler method return value: false]
OfficerRegistrationController
package com.crimetrack.web;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.apache.log4j.Logger;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.crimetrack.business.Login;
import com.crimetrack.business.Officers;
import com.crimetrack.service.DivisionManager;
import com.crimetrack.service.GenderManager;
import com.crimetrack.service.OfficerRegistrationValidation;
import com.crimetrack.service.PositionManager;
import com.crimetrack.service.ValidateUserNameManager;
#Controller
public class OfficerRegistrationController {
private final Logger logger = Logger.getLogger(getClass());
private DivisionManager divisionManager;
private PositionManager positionManager;
private GenderManager genderManager;
private Officers officer = new Officers();
private ValidateUserNameManager validateUserNameManager;
Map<String, Object> myDivision = new HashMap<String, Object>();
Map<String, Object> myPosition = new HashMap<String, Object>();
Map<String, Object> myGender = new HashMap<String, Object>();
OfficerRegistrationValidation validateData = new OfficerRegistrationValidation();
#InitBinder("officers")
protected void initBinder(WebDataBinder binder){
//removes white spaces
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
//formats date
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
//By passing true this will convert empty strings to null
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
dateFormat.setLenient(false);
binder.setValidator(new OfficerRegistrationValidation());
}
#RequestMapping(value="officer_registration.htm", method = RequestMethod.GET)
public ModelAndView loadPage(HttpServletRequest request,
HttpServletResponse response,#ModelAttribute Officers officer, BindingResult result, ModelMap m, Model model) throws Exception {
try{
logger.debug("In Http method for OfficerRegistrationController");
myDivision.put("divisionList", this.divisionManager.getDivisions());
myPosition.put("positionList", this.positionManager.getPositionList());
myGender.put("genderList", this.genderManager.getGenderList());
model.addAttribute("division", myDivision);
model.addAttribute("position", myPosition);
model.addAttribute("gender", myGender);
return new ModelAndView("officer_registration");
}catch(Exception e){
request.setAttribute("error",e.getMessage());
return new ModelAndView("error_page");
}
}
#RequestMapping(value="officer_registration.htm", method=RequestMethod.POST)
public ModelAndView handleRequest(#Valid #ModelAttribute Officers officer, BindingResult result, ModelMap m, Model model)throws Exception{
if(result.hasErrors()){
model.addAttribute("division", myDivision);
model.addAttribute("position", myPosition);
model.addAttribute("gender", myGender);
return new ModelAndView("officer_registration");
}else{
return null;
}
}
#RequestMapping(value="validateUserName.htm", method=RequestMethod.GET)
public boolean validateUserName(#RequestParam String userName, #ModelAttribute Officers officer, BindingResult result, ModelMap m)throws Exception{
try{
logger.debug("Inside Controller validateUserName");
logger.debug("The user name that came in is " + userName);
if (validateUserNameManager.DoesUserNameExist(userName)== true){
return true;
}
return false;
// return true;
}catch(Exception e){
logger.debug("Error in validateUserName Controller " + e.getMessage());
return false;
}
}
public void setDivisionManager(DivisionManager divisionManager){
this.divisionManager = divisionManager;
}
public void setPositionManager(PositionManager positionManager){
this.positionManager = positionManager;
}
public void setGenderManager(GenderManager genderManager){
this.genderManager = genderManager;
}
/**
* #return the validateUserNameManager
*/
public ValidateUserNameManager getValidateUserNameManager() {
return validateUserNameManager;
}
/**
* #param validateUserNameManager the validateUserNameManager to set
*/
public void setValidateUserNameManager(
ValidateUserNameManager validateUserNameManager) {
this.validateUserNameManager = validateUserNameManager;
}
/**
* #return the officer
*/
public Officers getOfficer() {
return officer;
}
/**
* #param officer the officer to set
*/
public void setOfficer(Officers officer) {
this.officer = officer;
}
}
Per Spring's #RequestMapping documentation:
Any other return type will be considered as single model attribute to be exposed to the view, using the attribute name specified through ModelAttribute at the method level (or the default attribute name based on the return type's class name otherwise). The model will be implicitly enriched with command objects and the results of ModelAttribute annotated reference data accessor methods.
Because this method has the ModelAttribute annotation on an Officers object, the return type is expected to be an Officers object.
You probably want this method to return void, and write to the response object yourself. (To do that, you will need to add an HttpServletResponse parameter to your method.)
Alternatively, you could return a JSON view. See spring: return JSON from controller as ModelAndVIew
For example:
public View validateUserName(#RequestParam String userName, ModelMap m) {
// Do validation
m.addAttribute("isValid", validationResult);
return new MappingJacksonJsonView();
}
It appears you are running this query:
SELECT userName FROM crimetrack.tblofficers WHERE userName = 'hello'
The query runs successfully, but there is no record in the table matching userName = 'hello', so an empty result set is returned. Creating the officer then fails because there is no officer to create and that condition was not handled.
Run the query standalone and confirm there is no such record. Then look at your mapping code and see how this condition should be handled.
A follow up... The java docs for JdbcTemplate.queryForObject state:
This method is useful for running static SQL with a known outcome. The
query is expected to be a single row/single column query; the returned
result will be directly mapped to the corresponding object type.
...
Throws: IncorrectResultSizeDataAccessException - if the query does not
return exactly one row, or does not return exactly one column in that
row
So you this should not be called if you are not assured of a record in the db, otherwise the line:
String dbUserName = (String)getJdbcTemplate().queryForObject(sql, new Object[]{userName},String.class);
needs to be wrapped with a try-catch to handle this case.
I'm new to grails and am trying to get some tests running. I have two classes:
class Category {
String name;
}
class Animal {
Category category1
Category category2
boolean addCategory(Category category) {
if (!category1) {
category1 = category
return true
}
else if (!category2) {
category2 = category
return true
}
return false
}
boolean hasCategory(Category category) {
return category1 == category || category2 == category
}
}
Now I wrote a test that should check that adding more than two categories fails and that the third category would not be part of the categories:
class AnimalTests extends GrailsUnitTestCase {
protected void setUp() {
super.setUp()
}
protected void tearDown() {
super.tearDown()
}
void testMaximumCategories() {
Category category1 = new Category(name: "Category 1")
Category category2 = new Category(name: "Category 2")
Category category3 = new Category(name: "Category 3")
Animal animal = new Animal(title: "Animal")
assertTrue(animal.addCategory(category1))
assertTrue(animal.addCategory(category2))
assertFalse(animal.addCategory(category3))
assertTrue(animal.hasCategory(category1))
assertTrue(animal.hasCategory(category2))
assertFalse(animal.hasCategory(category3))
}
}
This test always fails in the last line and the stacktrace is the following
null
junit.framework.AssertionFailedError: null
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.assertTrue(Assert.java:20)
at junit.framework.Assert.assertFalse(Assert.java:34)
at junit.framework.Assert.assertFalse(Assert.java:41)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1323)
at groovy.lang.ExpandoMetaClass.invokeStaticMethod(ExpandoMetaClass.java:1082)
at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.callStatic(StaticMetaClassSite.java:62)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:165)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:173)
at animal.AnimalTests.testMaximumCategories(AnimalTests.groovy:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
...
What am I doing wrong?
When I copy/pasted your code it failed since there's no title property in the Animal class. This might be an artifact of converting real code to demo code, but it could cause some compiler weirdness. Try running grails clean to force a full compile. Once I added a title field it worked fine.