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.
Related
I have a simple class that uses a service called ReportingService. It gets injected into the class and I am verifying that it is called and with the expected arguments. The mock, returns the ReportSummary object i want to assert in the tests, by ensuring reportType and the other values meet the expectations. Unfortunately, the ReportSummary fields are all null, what am i doing wrong?
class ReportSummary {
String reportType
Date createdTime
String reportedById
}
class ReportingService {
ReportSummary updateReport(Report reportData) {
...
}
}
This Service is injected into a class PricingService like this:
class PricingService {
#Autowired
ReportingService reportingService
ReportingSummary updatePricingDetails( ReportData data) {
reportingService.updateReport(data)
}
}
The class is used in the service like this
class PricingServiceSpec extends Specification {
ReportingService reportingService = Mock()
PricingService pricingService = new PricingService( reportingService)
ReportData data = new ReportData(........)
def "Should return summary report data" (){
given:
Date today = new Date (System.currentMillis())
ReportSummary summary = new ReportSummary(reportType: 'Pricing',createdTime:
today, reportedById: 'GXT111111345')
when:
ReportSummary response = pricingService.updatePricingDetails(data)
then:
1 * reportingService.updateReport( data : {
assert it.pricingDescription == 'Pricing for Produce'
}) >> summary
response.reportType == 'Pricing' // The reportType is null why?
response.reportedById == 'GXT111111345' // The reportById is null, why? The
0 * _
)
}
}
Here is some example code which at least compiles and kind of emulates your situation, even though it returns some dummy data (but at least different from the stub result you want to test):
package de.scrum_master.stackoverflow.q67912725
class ReportData {
String pricingDescription;
}
package de.scrum_master.stackoverflow.q67912725
class ReportSummary {
String reportType
Date createdTime
String reportedById
}
package de.scrum_master.stackoverflow.q67912725
class ReportingService {
ReportSummary updateReport(ReportData reportData) {
return new ReportSummary(
reportType: "real report",
createdTime: new Date(),
reportedById: "me"
)
}
}
package de.scrum_master.stackoverflow.q67912725
import org.springframework.beans.factory.annotation.Autowired
class PricingService {
#Autowired
ReportingService reportingService
ReportSummary updatePricingDetails(ReportData data) {
reportingService.updateReport(data)
}
}
Here is a passing test. Your basic problem was that you tried to use a method parameter name in a method constraint, i.e. in your original code the data : part before the asserting closure. Method arguments are matched by type and position, not by parameter name. Omit that, and you are fine.
BTW, you also should not use assert in the method parameter constraint, but a simple boolean expression. A failed assertion would make the test fail, which is not what you want. You simply want to match a parameter value.
Fixing the test was not so difficult for me. It took me 10 times longer to actually make this mess compile and do something logical in order to even begin to analyse the test.
package de.scrum_master.stackoverflow.q67912725
import spock.lang.Specification
class PricingServiceTest extends Specification {
def reportingService = Mock(ReportingService)
def pricingService = new PricingService(reportingService: reportingService)
def reportData = new ReportData(pricingDescription: 'Pricing for Produce')
def "Should return summary report data"() {
given:
ReportSummary stubbedSummary = new ReportSummary(
reportType: 'Pricing',
createdTime: new Date(),
reportedById: 'GXT111111345'
)
when:
ReportSummary reportSummary = pricingService.updatePricingDetails(reportData)
then:
1 * reportingService.updateReport(
{ it.pricingDescription == 'Pricing for Produce' }
) >> stubbedSummary
reportSummary.reportType == stubbedSummary.reportType
reportSummary.reportedById == stubbedSummary.reportedById
0 * _
}
}
I'm upgrading an inherited Grails 2 app to 3.3.10. We have controller methods that rely on Domain class validation to control logic flow, but we can't get DomainClass validation to work in ControllerUnitTests when running in Grails 3
For example,
Gift and RecipientAddress are DomainClasses and RecipientAddress.hasErrors() is used to validate against the RecipientAddress constraints.
def confirmAddress() {
Gift gift = Gift.get(params.giftId)
if (!gift) {
render(view: "index", model: [invalid: true])
return
}
recipientAddress = recipientAddressService.storeAddressInformation(params, gift)
if (recipientAddress.hasErrors()) {
render(view: "index", model: getAddressErrorModel(gift, recipientAddress))
return;
} else {
return [
recipientAddress : recipientAddress,
gift : gift
]
}
}
In the following test, when I debug the controller method it does everything expected but recipientAddress.hasErrors() always returns true and the test fails.
ie:
#Transactional
class GiftDetailsControllerTest extends Specification implements ControllerUnitTest<GiftDetailsController> {
#Shared
#AutoCleanup
SimpleMapDatastore dataStore = new SimpleMapDatastore([ConnectionSource.DEFAULT, "reporting"],
RecipientAddress, Gift)
def setup() {
controller.recipientAddressService = Mock(RecipientAddressService)
}
void "test RecipientAddress Bad PhoneNumber"() {
given:
RecipientAddress recipientAddress = new RecipientAddress(
phone: '123-456-789'
)
UnitTestDataFactory dataFactory = UnitTestDataFactory.getDataFactory()
Gift gift = dataFactory.getMockGift()
gift.save()
params.giftId = gift.id
when:
recipientAddress.validate()
controller.confirmAddress()
then:
recipientAddress.hasErrors()
recipientAddress.getErrors().getFieldError('phone')
1 * controller.recipientAddressService.storeAddressInformation(params, gift) >> recipientAddress
view == '/giftDetails/index'
}
}
Implementing DataTest ie: ...implements ControllerUnitTest<GiftDetailsController>, DataTest { fixes the DomainClass validation, but breaks the controllers ability to get the saved Gift.
Is there a way get DomainClass validation working in a ControllerUnit test?
Fix
Implemented DataTest with mockDomains and had to remove the custom dataStore.
#Transactional
class GiftDetailsControllerTest extends Specification implements ControllerUnitTest<GiftDetailsController>, DataTest {
// #Shared
// #AutoCleanup
// SimpleMapDatastore dataStore = new SimpleMapDatastore([ConnectionSource.DEFAULT, "reporting"], RecipientAddress, Gift)
void setupSpec() {
mockDomains RecipientAddress, Gift
}
....
Is there a way get DomainClass validation working in a ControllerUnit
test?
Yes.
You probably want something like this...
class GiftDetailsControllerTest extends Specification implements ControllerUnitTest<GiftDetailsController>, DataTest {
Class[] getDomainClassesToMock() {
[Gift]
}
// ...
}
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 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?