I'm trying to test a Room database in Android, written in Kotlin, locally; that is not on an emulator and without instrumented testing. As I understand it this is possible using the Roboelectric framework but I'm having some trouble with this :
How does one select the appropriate class for the RunWith(CLASS) decorator ?
I understand AndroidJUnit4 is necessary for instrumented tests, given that this is a local test should I be using JUnit4 instead or some other derivative from RoboElectric.
How should I correctly determine the context ?
Trying InstrumentationRegistry.getTargetContext() requires that I use InstrumentationRegistry which isn't available when testing locally or that test can not be imported when importing androidx.test.platform.app.InstrumentationRegistry or android.support.test.InstrumentationRegistry. Trying ApplicationProvider.getApplicationContext() claims the reference getApplicationContext can't be found. I'm also not sure where I should be importing either InstrumentationRegistry or ApplicationProvider from.
In general I'm finding it tricky to determine the appropriate libraries to use in Java; all the documentation appears very version specific and assumes you magically know where to import a given class from where often such a classes appear in more then one library. Then package imported through gradle also seems to be well related but does not explicitly match the package being imported. If you have any general tips on this I would be quite keen to hear it.
My code so far is as follows:
package com.manaikan.airvendor.AirTime
import android.content.Context
import android.arch.persistence.room.Room
import androidx.test.platform.app.InstrumentationRegistry
import com.manaikan.airvendor.airtime.AirVendorDatabase
import com.manaikan.airvendor.airtime.BundleQuery
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import java.io.IOException
// Roboelectric
import androidx.test.core.app.ApplicationProvider
#RunWith(JUnit4::class)
class BundleTest {
private lateinit var queryset : ENTITYDao
private lateinit var database : APPLICATIONDatabase
#Before
fun setup()
{
val context = ApplicationProvider.getApplicationContext<Context>()
database = Room.inMemoryDatabaseBuilder(context, APPLICATIONDatabase::class.java)
.allowMainThreadQueries()
.build()
queryset = database.bundleQuery()
}
#After
#Throws(IOException::class)
fun tearDown()
{
database.close()
}
#Test
#Throws(Exception::class)
fun review()
{
}
}
It seems to me you were almost there. The main thing to change is the runner, use: AndroidJUnit4, and maybe the version of the dependencies. Assuming your database and DAO are set up correctly, this should work (add import for your classes):
package com.manaikan.airvendor.AirTime
import android.content.Context
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.io.IOException
#RunWith(AndroidJUnit4::class)
class BundleTest {
private lateinit var queryset : ChannelProgramsDao
private lateinit var database : ChannelProgramsDatabase
#Before
fun setup()
{
val context = ApplicationProvider.getApplicationContext<Context>()
database = Room.inMemoryDatabaseBuilder(context, APPLICATIONDatabase::class.java)
.allowMainThreadQueries()
.build()
queryset = database.bundleQuery()
}
#After
#Throws(IOException::class)
fun tearDown()
{
database.close()
}
#Test
#Throws(Exception::class)
fun review()
{
}
}
It worked for me with the following dependencies:
testImplementation "org.robolectric:robolectric:4.2"
testImplementation "androidx.test.ext:junit:4.12"
implementation "androidx.room:room-runtime:2.2.2"
implementation "androidx.room:room-ktx:2.2.2"
kapt "androidx.room:room-compiler:2.2.2"
testImplementation "androidx.room:room-testing:2.2.2"
Related
When writing unit tests in Grails 3.x, we have to mock domains. Here is the example code.
package com.example.service
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import spock.lang.Ignore
import spock.lang.Specification
#TestFor(SomeService)
#Mock([DomainA, DomainB])
class SomeServiceSpec extends Specification{
...
}
The problem is when a new domain is added, lets say DomainC and the unit tests are dependent upon DomainC, then those unit tests fails. We then have to manually have to add DomainC.
Is there a way to dynamically mock the domains?
#TestFor(SomeService)
#Mock([dynamically mock all domain objects here])
class SomeServiceSpec extends Specification{
...
}
Maybe this is what you need (from grails doc).
Alternatively you can also use the DomainClassUnitTestMixin directly
with the TestMixin annotation and then call the mockDomain method to
mock domains during your test:
#TestFor(BookController)
#TestMixin(DomainClassUnitTestMixin)
class BookControllerSpec extends Specification {
void setupSpec() {
mockDomain(Book)
}
...
Also mockDomains method exists for the list of domains, which you can retrieve by standard way from context.
Mocking a method that is a dependancy is not working for me. When the method I need to test is calling its dependancy method, the real method is called instead of the mock version of it.
I do have the following files:
myLibrary.py
from src.myOtherLibrary import myOtherLibrary
class myLibrary():
def __init__():
self.myVar = myOtherLibrary() #dependancy
def my_method():
method1 = self.method1()
externalMethod2 self.myVar.method2() #method2 called from the external class myOtherLibrary
return method1 + externalMethod2
def method1():
return "method1 from myLibrary..."
src/myOtherLibrary.py
class myOtherLibrary():
def method2():
return "method2 from myOtherLibrary..."
Finally the Unit Test:
TestMyLibrary.py
import unittest
import mock
from myLibrary import myLibrary
from src.myOtherLibrary import myOtherLibrary
class TestMyLibrary(unittest.TestCase):
#mock.patch('myLibrary.myLibrary.method1') #mocking this works because it's a sibling method from my_method() to test
#mock.patch('src.myOtherLibrary.myOtherLibrary.method2') #this does not work because it's an external class from myLibrary
def test_my_method(my_method1_to_mock, my_method2_to_mock):
my_method1_to_mock.return_value = "something_to_return.."
my_method2_to_mock.return_value = "something_else_to_return.."
myLibraryVar = myLibrary()
result = myLibraryVar.my_method()
print result #I would expect to see this: "something_to_return..something_else_to_return.."
#But it actually prints this: "something_to_return..method2 from myOtherLibrary..."
#So mocking is not working for method2
self.assertEqual('something_to_return..something_else_to_return..', result)
if __name__ == '__main__':
unittest.main()
Perhaps it's important to mention that myLibrary.py and TestMyLibrary.py are in the same folder, but myOtherLibrary.py is under different folder level.
I hope you can help me find what I'm missing here.
Any suggestion will be very well appreciated.
Thanks.
You can't patch like that because the methods you are trying to mock are class methods not functions. So you need to use patch.object.
#mock.patch.object(myLibrary, 'method1')
#mock.patch.object(myOtherLibrary, 'method2')
...
I am trying to build an akka based system which will periodically(every 15 second) send REST request, do some filter, some data cleansing and validation on the received data and save into HDFS.
Below is the code that I wrote.
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.{Flow, Sink, Source}
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{HttpRequest, HttpResponse, StatusCodes}
import akka.actor.Props
import akka.event.Logging
import akka.actor.Actor
import scala.concurrent.{ExecutionContext, Future}
import scala.util.Try
import akka.http.scaladsl.client.RequestBuilding._
/**
* Created by rabbanerjee on 4/6/2017.
*/
class MyActor extends Actor {
val log = Logging(context.system, this)
import scala.concurrent.ExecutionContext.Implicits.global
def receive = {
case j:HttpResponse => log.info("received" +j)
case k:AnyRef => log.info("received unknown message"+k)
}
}
object STest extends App{
implicit val system = ActorSystem("Sys")
import system.dispatcher
implicit val materializer = ActorMaterializer()
val ss = system.actorOf(Props[MyActor])
val httpClient = Http().outgoingConnection(host = "rest_server.com", port = 8080)
val filterSuccess = Flow[HttpResponse].filter(_.status.isSuccess())
val runnnn = Source.tick(
FiniteDuration(1,TimeUnit.SECONDS),
FiniteDuration(15,TimeUnit.SECONDS),
Get("/"))
.via(httpClient)
.via(filterSuccess)
.to(Sink.actorRef(ss,onCompleteMessage = "done"))
runnnn.run()
}
The problem I am currently facing is,
Even though I used a repeat/tick with source, I can see the result once. It's not repetitively firing the request.
I am also trying to find grouping the result of say 50 such request, coz as I will be writing it to hadoop, I cant write every request, as it will flood HDFS with multiple file.
You are not consuming the responses you are getting back from the HTTP call. It is compulsory to consume the entity bytes returned by Akka HTTP, even if you are not interested in them.
More about this can be found in the docs.
In your example, as you are not using the response entity, you can just discard its bytes. See example below:
val runnnn = Source.tick(FiniteDuration(1,TimeUnit.SECONDS),FiniteDuration(15,TimeUnit.SECONDS),Get("/"))
.via(httpClient)
.map{resp => resp.discardEntityBytes(); resp}
.via(filterSuccess)
.to(Sink.actorRef(ss,onCompleteMessage = "done"))
I was wondering as to how to build up a world of Domain class objects to use in my unit tests. What´s the best approach?
Say this is my code, ServiceX:
List<Course> getAllCoursesByType(String type) {
List<Course> list = Course.findAllByType(type)
list
}
This is the test for ServiceX:
import grails.buildtestdata.mixin.Build
import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.Specification
#TestFor(ServiceX)
class ServiceXSpec extends Specification {
void "get all open courses"() {
given:
String type = "open"
when:
def list = service.getAllCoursesByType(type)
then:
list.size() == 4
}
}
How can I "pre populate" the test-db (memory) sow that I actually have 4 such objects in the list?
Create integration test for this. See an example here.
This is a judgement call for when to test using a slow integration test. The key is to test your code, not the Grails/hibernate DB code.
Integration tests should not be needed for the bulk of the service testing. I do think you need an integration test for the object interactions in a running system with a real DB. I tend to do that in GUI tests using GEB. These tests usually cover basic end-to-end scenarios. That tests the server side and the GUI interaction with the server.
In the GUI/GEB tests, I don't test all permutations and edge conditions of the service. I do most of that edge testing in unit tests.
I have found that with Grails, if one simple DB action works in an integration test, then most other simple DB actions work. The Grails domain mocks for save(), delete(), etc simulate the 'real' DB actions fairly well. Note: they do operate on objects in memory, so it is not exactly the same.
I don't use Spock, but with JUnit I use this approach (still works with Grails 3):
#TestFor(ServiceX)
#Mock([Course])
class ServiceXTests {
}
#Test
void testXYZ() {
def course= new Course(course: 'ABC')
assert course.save()
. . .
}
This appears to be supported with Spock. I would assume this creation of domain records belongs in the Spock 'given' section. Also, see Grails Testing.
Another great resource is to search the Grails source on Github. I learned a lot from their examples.
It turns out you can add / override methods to the domain classes (for example), something like this:
import grails.buildtestdata.mixin.Build
import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.Specification
import grails.test.mixin.Mock
#Mock([Course])
#TestFor(ServiceX)
class ServiceXSpec extends Specification {
void "get all open courses"() {
given:
String type = "open"
Course.metaclass.static.findAllByType = { String type -> [new Course()]}
when:
def list = service.getAllCoursesByType(type)
then:
list.size() == 1
}
}
I have a basic mapping defined in my UrlMappings.groovy If I run my app and go to /api/address/zip-code/12345 I get the show action to respond to the browsers request.
group("/api/address"){
"/zip-code"( resources: 'zipCode', includes: ['show'] )
}
I am trying to create a test to validate that my mapping works because I am going to create a ton of mappings here and I want them to backed by a test. This is my test.
package com.vega.foo
import com.vega.foo.address.ZipCodeController
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import spock.lang.Specification
import org.codehaus.groovy.grails.web.mapping.UrlMappings
#TestFor(UrlMappings)
#Mock(ZipCodeController)
class UrlMappingsSpec extends Specification {
void "test zip code mapping"() {
expect:
assertForwardUrlMapping("/api/address/zip-code/12345", controller: 'zipCode', action: "show")
}
}
When I try and run this test I get the following error.
Compilation error compiling [unit] tests: BUG! exception in phase
'instruction selection' in source unit
'C:\websites********\test\unit\com\vega\foo\UrlMappingsSpec.groovy'
unexpected NullpointerException
This is about as basic of a URL Mappings test as you can write. What am I missing here?
PR. This is how I was able to pass unit spec.
Changes are almost what I had in comments.
Adding $id to url mapping.
Remove import org.codehaus.groovy.grails.web.mapping.UrlMappings from test.
Specifying the controller and the action explicitly in UrlMapping.