I'm trying to test a method in my service but I keep getting error that
String-based queries like [findAll] are currently not supported in this
implementation of GORM. Use criteria instead.
My service:
class MyService {
List<Color> colorShade (String shade) {
def shadeId = Shade.findByName(shade).id
return ColorShade.get(shadeId)
}
}
My class that joins Shade and Color domains
class ColorShade extends Serializable {
Color color
Shade shade
static ColorShade create (Color color, Shade shade, boolean flush = false) {
if (get(shade.id) == null)
new ColorNetwork(color: color, shade: shade).save(flush: flush)
}
static ColorShade get (long shadeId) {
ColorShade.findAll 'from ColorShade where shade.id = :shadeId',
[shadeId: shadeId]
}
static mapping = {
table 'color_shade'
version false
id composite: ['color', 'shade']
}
}
My Spec: test\unit\MyServiceSpec.groovy I've also tried adding it to test\integration\MyServiceSpec.groovy
#TestFor(MyServiceSpec)
#Mock([Color, Shade, ColorNetwork])
#TestMixin(DomainClassUnitTestMixin)
class MyServiceSpec extends Specification {
def shade
def color
def setup(){
color = new Color(name: "red")
shade = new Shade(name: "dark")
color.save(flush: true)
shade.save(flush: true)
ColorShade.create(color, shade)
/*
I've also tried:
mockDomain(ColorShade, [[color: color, shade: shade]])
but I get the same error
*/
}
def cleanup () {
}
def "test colorShade" () {
expect:
1 == service.colorShade("dark").size()
}
}
When I run this test I get an error:
String-based queries like [findAll] are currently not supported in this implementation of GORM. Use criteria instead.
Question
How can I test this ? I am on grails 2.2.4
Note: This is just a sample test scenario I've created for purpose of the question. My actual tests are different but in them I have the same problem as this question.
If you are using version 4.3.5.4 or later of the hibernate4 plugin then you can use the grails.test.mixin.hibernate.HibernateTestMixin, which supports a full Hibernate GORM in your unit test environment. You need to add that as a dependency with something like this in grails-app/conf/BuildConfig.groovy.
dependencies {
test "org.grails:grails-datastore-test-support:1.0-grails-2.4"
}
Then annotate your test with the grails.test.mixin.hibernate.HibernateTestMixin annotation.
Related
I have a Grails service that creates a criteria query with optional parameters like this:
List<Car> search(String make = "%", String model = "%", Integer year = null) {
def c = Car.createCriteria()
return c.list() {
if(make) {
like("make", make)
}
if(model) {
like("model", model)
}
if(year) {
eq("year", year)
}
}
}
(Also, is this the idiomatic way to do this in grails? I'm quite new to the framework and I'm trying to find the right way to do things)
I'd like to test that the proper criteria filters are set according to the values of the parameters of the search method but I'm having no success.
I tried some variations of this:
#TestFor(CarService)
#Mock(Car)
class CarServiceSpec extends Specification {
def car = Mock(Car)
void "empty filters"() {
when: service.search()
then:
with(car.createCriteria()) {
0 * like(*_)
0 * eq(*_)
}
}
}
But I can't seem to find a way to do assertions about the interactions between the CarService and the criteria object.
What am I missing?
The Grails Where query instead of the Criteria query seems to be better choice for an idiomatic way to do this in Grails:
Gorm Where Query
Given the following setup:
class MockingFilters {
def filters = {
all(controller:"simple", action:"list") {
before = {
log.info "This needs asserting"
return false
}
}
}
}
Is there a way to assert that the log.info has fired? I am unsure how to get a handle on the Filter, and thus be able to interaction test the log object.
void "test list action is filtered"() {
when:
withFilters(action:"list") {
// Important bit
// Not sure how to get a handle to the filter
1 * log.info("This needs asserting")
controller.list()
}
then:
// Whatever here
}
There are also other objects on the Filter that I would like to test, but this example should be reflective of those too.
In the below class, I just need RevShareFormula.withCriteria to return a result,
but getting the exception in resultTransformer() method.
Can anyone tell me how to Mock the below method so that i get some result from withCriteria
Here is the class:
class PartnerFinancialService {
def getPartnerPayeeRevenuShareDetails(long partnerPayeeId, def contextTypeCode) {
def partnerPayeesRevShareFormula = RevShareFormula.withCriteria {
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
createAlias('partnerRevShareConfig', 'partnerRevShareConfig')
createAlias('pricingModel', 'pricingModel')
createAlias('partnerRevShareConfig.revshareCategory', 'revshareCategory')
and {
eq("revshareCategory.payeeProfileId", partnerPayeeId)
eq("revshareCategory.referenceContextTypeCode", contextTypeCode)
isNull("partnerRevShareConfig.revshareValidToDate")
}
projections {
property("id", "formulaId")
property("pricingModel.id", "pricingModelId")
property("pricingModel.pricingName", "pricingName")
property("pricingModel.pricingType", "pricingType")
..
..
}
}
}
Here is the test class
#TestFor(PartnerFinancialService)
#Mock(RevShareFormula)
class PartnerFinancialServiceSpec extends Specification {
void "test getPartnerPayeeRevShareDetails"() {
def partnerPayeeRevShare = new PartnerRevShareConfig()
partnerPayeeRevShare.id = 1
def revShareModel = new PricingModel();
revShareModel.id = 1
def partnerPayeeRevShareFormula = new RevShareFormula();
partnerPayeeRevShareFormula.id=5
partnerPayeeRevShareFormula.pricingModel = revShareModel
partnerPayeeRevShareFormula.partnerRevShareConfig = partnerPayeeRevShare
partnerPayeeRevShareFormula.revshareFormula = "revshare*10"
partnerPayeeRevShareFormula.revshareTierHighValue = 0
partnerPayeeRevShareFormula.revshareTierLowValue= 0
RevShareFormula.metaClass.static.withCriteria = {partnerPayeeRevShareFormula}
when:
def result = service.getPartnerPayeeRevenuShareDetails(1,"PKG")
then:
//assert result.pricingModel.id == 1
println "Succesfully Fetched from DB"
}
}
Getting the following exception.
<testcase classname="com.orbitz.dat.partners.PartnerFinancialServiceSpec" name="test getPartnerPayeeRevShareDetails" time="0.039">
<error message="No signature of method: com.orbitz.dat.partners.PartnerFinancialService.resultTransformer() is applicable for argument types: (org.hibernate.transform.AliasToEntityMapResultTransformer) values: [org.hibernate.transform.AliasToEntityMapResultTransformer#3632aa4]" type="groovy.lang.MissingMethodException">groovy.lang.MissingMethodException: No signature of method: com.orbitz.dat.partners.PartnerFinancialService.resultTransformer() is applicable for argument types: (org.hibernate.transform.AliasToEntityMapResultTransformer) values: [org.hibernate.transform.AliasToEntityMapResultTransformer#3632aa4]
at com.orbitz.dat.partners.PartnerFinancialService.$tt__getPartnerPayeeRevenuShareDetails_closure24(PartnerFinancialService.groovy:39)
at grails.gorm.CriteriaBuilder.invokeClosureNode(CriteriaBuilder.java:1093)
at grails.gorm.CriteriaBuilder.invokeMethod(CriteriaBuilder.java:314)
at org.grails.datastore.gorm.GormStaticApi.withCriteria_closure11(GormStaticApi.groovy:304)
at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:302)
at org.grails.datastore.gorm.AbstractDatastoreApi.execute(AbstractDatastoreApi.groovy:37)
at org.grails.datastore.gorm.GormStaticApi.withCriteria(GormStaticApi.groovy:303)
at com.orbitz.dat.partners.PartnerFinancialService.$tt__getPartnerPayeeRevenuShareDetails(PartnerFinancialService.groovy:38)
at com.orbitz.dat.partners.PartnerFinancialServiceSpec.test getPartnerPayeeRevShareDetails(PartnerFinancialServiceSpec.groovy:71)
Use an integration test. Never test ORM code with unit tests. I know it's slower and the experience is less enjoyable, but you are fooling yourself if you think that you are actually testing something related to database queries with this test. You are testing the testing framework of grails (the in-memory GORM implementation)
I am using shiro security in my grail application.
Grails version : 2.2.1
shiro : 1.2.0
I have a problem in writing grails unit test case for the controller with filter enabled. When the test case run without filters then it is working fine, if it runs withFilters then it is failing for accessControl() method not found in the controller. I dont know how to make Shiro's api to be visible while running the test case.I referred shiro unit test case link http://shiro.apache.org/testing.html but I couldn't get any info regarding accessControl().I have given sample code how my classes and test case looks like
MyController.groovy
def create() {
// getting request parameters and validation
String emailId = params.emailId
def ret = myService.createUser(emailId)
return ret
}
MyControllerFilters.groovy
def filters = {
loginCheck(controller: 'user') {
before = {
//do some business checks
// Access control by convention.
accessControl() // This is a dynamic method injected by ShiroGrailsPlugin to FilterConfig, but this is not visible during the test case.
}
}
MyControllerTests.groovy
#TestFor(MyController)
#Mock(MyControllerFilters)
class MyControllerTests {
#Before
void setup() {
// initializing some variables
}
void testCreateUserWithFilter() {
request.accessAllowed = true
withFilters(action:"create") {
controller.create()
}
assert response.message == "success"
}
}
Try to use:
ControllerOrService.metaClass.method = {
return "" //what you need to be returned
}
Add parameters to closure if method take parameters:
ControllerOrService.metaClass.method = { def a, def b ->
return a + b
}
Don't forget to use full name of method when you mock them in that way.
I'm having some problems with making my tests insert fake data in my database. I've tried a few approaches, without luck. It seems that Global.onStart is not run when running tests within a FakeApplication, although I think I read that it should work.
object TestGlobal extends GlobalSettings {
val config = Map("global" -> "controllers.TestGlobal")
override def onStart(app: play.api.Application) = {
// load the data ...
}
}
And in my test code:
private def fakeApp = FakeApplication(additionalConfiguration = (
inMemoryDatabase().toSeq +
TestGlobal.config.toSeq
).toMap, additionalPlugins = Seq("plugin.InsertTestDataPlugin"))
Then I use running(fakeApp) within each test.
The plugin.InsertTestDataPlugin was another attempt, but it didn't work without defining the plugin in conf/play.plugins -- and that is not wanted, as I only want this code in the test scope.
Should any of these work? Have anyone succeeded with similar options?
Global.onStart should be executed ONCE (and only once) when the application is launched, whatever mode (dev, prod, test) it is in. Try to follow the wiki on how to use Global.
In that method then you can check the DB status and populate. For example in Test if you use an in-memory db it should be empty so do something akin to:
if(User.findAll.isEmpty) { //code taken from Play 2.0 samples
Seq(
User("guillaume#sample.com", "Guillaume Bort", "secret"),
User("maxime#sample.com", "Maxime Dantec", "secret"),
User("sadek#sample.com", "Sadek Drobi", "secret"),
User("erwan#sample.com", "Erwan Loisant", "secret")
).foreach(User.create)
}
I chose to solve this in another way:
I made a fixture like this:
def runWithTestDatabase[T](block: => T) {
val fakeApp = FakeApplication(additionalConfiguration = inMemoryDatabase())
running(fakeApp) {
ProjectRepositoryFake.insertTestDataIfEmpty()
block
}
}
And then, instead of running(FakeApplication()){ /* ... */}, I do this:
class StuffTest extends FunSpec with ShouldMatchers with CommonFixtures {
describe("Stuff") {
it("should be found in the database") {
runWithTestDatabase { // <--- *The interesting part of this example*
findStuff("bar").size must be(1);
}
}
}
}