grails 4 unit test controller could not find class - testing

I am using grails 4 to create unit test for controller
https://testing.grails.org/latest/guide/index.html
My controller is under grails-app/controllers/mypack/myfolder/exampleController.groovy
My unit test is under src/test/groovy/mypack/myfolder/exampleControllerSpec.groovy
my unit test is like this
class exampleControllerSpec extends Specification implements ControllerUnitTest< exampleController>
but it complain can not resolve symbol 'exampleController'
anything wrong here?
how to import exampleController

The project at https://github.com/jeffbrown/leecontrollertest demonstrates how to construct the test.
https://github.com/jeffbrown/leecontrollertest/blob/d6fc272a69406f71286bf5268794ef4a4252a15b/grails-app/controllers/mypack/myfolder/exampleController.groovy
package mypack.myfolder
// NOTE: The nonstandard class naming convention here is intentional
// per https://stackoverflow.com/questions/65723769/grails-4-unit-test-controller-could-not-find-class
class exampleController {
def hello() {
render 'Hello, World!'
}
}
https://github.com/jeffbrown/leecontrollertest/blob/d6fc272a69406f71286bf5268794ef4a4252a15b/src/test/groovy/mypack/myfolder/exampleControllerSpec.groovy
package mypack.myfolder
import grails.testing.web.controllers.ControllerUnitTest
import spock.lang.Specification
// NOTE: The nonstandard class naming convention here is intentional
// per https://stackoverflow.com/questions/65723769/grails-4-unit-test-controller-could-not-find-class
class exampleControllerSpec extends Specification implements ControllerUnitTest<exampleController> {
void "test action which renders text"() {
when:
controller.hello()
then:
status == 200
response.text == 'Hello, World!'
}
}

Related

How to create parameterized hooks in junit 5?

I am writing a test in using junit 5 where I want to run a same test on different sets of data. To achieve that, I am using parameterization. Now a situation came in where I want to run something before each set. I want to implement that in #BeforeEach hook and after some research, I found that ParameterResolver implementation can be one of the solution for that. But with that, test is getting issues to get parameter in #BeforeEach hook.
Here I am adding my code. These are kotlin classes. One test class StringDataClientTest which extends StringDataTest in which I am adding test parameter and #beforeEach hook. Adding #ExtendWith with this class which is extending StringParameterResolver class.
StringDataClientTest:
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class StringDataClientTest : StringDataTest() {
#DisplayName("First Client Test")
#ParameterizedTest
#MethodSource("getString")
fun firstClientTest(data: String) {
System.out.println("First client test for: $data")
}
}
StringDataTest:
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.params.provider.MethodSource
#ExtendWith(StringParameterResolver::class)
open class StringDataTest {
companion object {
#JvmStatic
fun getString(): List<String> {
return listOf(
"Parameter 1",
"Parameter 2",
"Parameter 3",
"Parameter 4"
)
}
}
#BeforeEach
#MethodSource("getString")
fun beforeEveryTest(value: String) {
System.out.println(" --------- Running before hook for: $value")
}
}
StringParameterResolver:
import org.junit.jupiter.api.extension.ExtensionContext
import org.junit.jupiter.api.extension.ParameterContext
import org.junit.jupiter.api.extension.ParameterResolver
class StringParameterResolver : ParameterResolver {
override fun supportsParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Boolean {
return parameterContext!!.parameter.type === StringDataTest::class.java
}
override fun resolveParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Any {
return StringDataTest()
}
}
And I am getting this exception in console output:
org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [java.lang.String arg0] in method [public final void com.thescore.test.cases.team.testCode.StringDataTest.beforeEveryTest(java.lang.String)].
Expecting:
Running before hook for: Parameter 1
First client test for: Parameter 1
Running before hook for: Parameter 2
First client test for: Parameter 2
Running before hook for: Parameter 3
First client test for: Parameter 3
Running before hook for: Parameter 4
First client test for: Parameter 4
Haven't done parameterized hooks before. Please help with this. Thanks!

Kotlin ArchUnit : How to set rules doesn't ask for object that belongs to kotlin language?

I'm trying to setup tests with Arch Unit to test my naming conventions and annotations.
I have this class:
#RestController
#RequestMapping("/uri")
class AnyController() : SomeResources {
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
override fun create(
#Valid #RequestBody requestDTO: requestDTO,
): ResponseEntity<ResponseDTO> {
when (algo) {
algo -> logger.debug("[algo: ${algo}]")
else -> logger.debug("[algo: ${algo}]")
}
return ResponseEntity.status(HttpStatus.CREATED).body(service.create(requestDTO))
}
companion object {
private val logger: Logger = LoggerFactory.getLogger(AnyController::class.java)
}
}
And my class Test is this one:
#AnalyzeClasses(packages = "some.package",
importOptions = {
ImportOption.DoNotIncludeTests.class,
ImportOption.DoNotIncludeJars.class,
ImportOption.DoNotIncludeArchives.class
})
class ArchitectureTest {
#ArchTest
public static final ArchRule controllers_name_classes_should_finish_with_Controller = ArchRuleDefinition.classes().that().resideInAPackage("..controller").should().haveSimpleNameEndingWith("Controller");
#ArchTest
public static final ArchRule controllers_classes_should_use_annotation_RestController = ArchRuleDefinition.classes().that().resideInAPackage("..controller").should().beAnnotatedWith(RestController.class);
}
But I get these errors:
java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'classes that reside in a package '..controller' should be annotated with #RestController' was violated (2 times):
Class <some.package.controller.AnyController$WhenMappings> is not annotated with #RestController in (AnyController.kt:0)
Class <some.package.controller.AnyController$Companion> is not annotated with #RestController in (AnyController.kt:0)
java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'classes that reside in a package '..controller' should have simple name ending with 'Controller'' was violated (2 times):
simple name of some.package.controller.AnyController$Companion does not end with 'Controller' in (AnyController.kt:0)
simple name of some.package.controller.AnyController$WhenMappings does not end with 'Controller' in (AnyController.kt:0)
I don't know how to tell arch unit ignore companion, when or something else that is not my class.
What am I doing wrong?
Maybe you want to restrict your conventions to top-level classes?
ArchRuleDefinition.classes()
.that().resideInAPackage("..controller")
.and().areTopLevelClasses()
.should().haveSimpleNameEndingWith("Controller")
.andShould().beAnnotatedWith(RestController.class);

Merging Activities in kotlin

I have three different activities which extends three different things and i want to implement multi level inheritance so that i can add it in android:name of androidmanifest.
Here are all activities. I don't know native development at all. Any help would be appreciated.
1st activity
package com.package
import hrx.plugin.monet.MonetApplication
class CustomApplication : MonetApplication()
2nd activity
package com.package
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}
3rd activity
package com.package;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugins.androidalarmmanager.AlarmService;
class Application : FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate();
AlarmService.setPluginRegistrant(this);
}
override fun registerWith(registry: PluginRegistry) {
GeneratedPluginRegistrant.registerWith(registry);
}
}
I have three different activities
Actually, you seem to have two different Application objects and one Activity. If you don't know the difference you may want to go back and take some Android 101 courses.
i want to implement multi level inheritance so that i can add it in android:name of androidmanifest.
OK. Well you have
class CustomApplication : MonetApplication()
and
class Application : FlutterApplication(), PluginRegistrantCallback
Looking at the definition of MonetApplication we see that it's defined as
open class MonetApplication : FlutterApplication()
So MonetApplication is a FlutterApplication so if you extend MonetApplication you are effectively also extending FlutterApplication, so you can basically merge your two existing classes into one:
class HighlanderApplication : MonetApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate();
AlarmService.setPluginRegistrant(this);
}
override fun registerWith(registry: PluginRegistry) {
GeneratedPluginRegistrant.registerWith(registry);
}
}
Now you can use HighlanderApplication in your manifest and get all the logic that was in both.

Spock: How to properly share features between implementations of Specification

I encountered an unfortunate aspect of Spock Framework (1.3-groovy-2.5), which I use for integration testing of a Gradle plugin.
The code sample
Parent class:
class ClassA extends Specification {
def setupSpec() {
System.out.println("In ClassA setupSpec()")
}
def "base feature"() {
expect:
true
}
}
Child class:
class ClassB extends ClassA {
#Override
def setupSpec() {
System.out.println("In ClassB setupSpec()")
}
def "extended feature"() {
expect:
true
}
}
When I run tests in ClassB, both versions of setupSpec() are called:
In ClassA setupSpec()
In ClassB setupSpec()
Of course, if I call method via native Groovy ways:
class Main {
static void main(String[] args) {
ClassB classB = new ClassB()
classB.setupSpec()
}
}
Then I see only what is expected:
In ClassB setupSpec()
So, evidently, this is a Spock feature of some kind.
Question
In practice, what is the suggested way of inheriting from implementations of Specification while overriding setup logic?
As documented in Fixture Method Invocation Order
If fixture methods are overridden in a specification subclass then
setup() of the superclass will run before setup() of the subclass.
cleanup() works in reverse order, that is cleanup() of the subclass
will execute before cleanup() of the superclass. setupSpec() and
cleanupSpec() behave in the same way. There is no need to explicitly
call super.setup() or super.cleanup() as Spock will automatically find
and execute fixture methods at all levels in an inheritance hierarchy.
The easiest way would be to just move the logic to another method that you can override.
class Base extends Specification {
def setupSpec() {
init()
}
def init() {
println "foo"
}
def "let's try this!"() {
expect:
Math.max(1, 2) == 2
}
}
class Sub extends Base {
#Override
def init() {
println "bar"
}
}
As documented, fixture methods are not meant to override each other but to complement each other, i.e. they are all called in a specific, logical order. Like you said, this is a feature.
Hence, my answer is: There is no suggested way to override setup logic. Instead, the suggested way is to design your base and derived specifications in such a way that overriding is not necessary. I never had any problems to do so and hope you shall solve your problem easily too.
Your sample code is too schematic to say anything more, but basically think about fixture methods in base classes as responsible for to setting up and cleaning up fixture fields in there, while derived specs' fixture methods would take care of additional fixtures specific to those classes. In your example there also is a feature method in the base spec, which I find rather strange because it would be executed for the base spec itself and each time a derived spec is executed. I rather like to think of base specs as practically abstract (avoiding to add any feature methods to them and them being picked up by the test runner), but I am sure there are cases in which what you sketched above might also be helpful. I just cannot think of one now.

Can't inherit, in Raku, a method trait from a class defined in the same file

A method trait, defined with trait_mod, is flawlessly inherited from a class defined in an other file.
This doesn't seem to be working when the two classes are defined in the same file.
The 2 following files are working fine together:
# mmm.pm6
class TTT is export {
multi trait_mod:<is> (Routine $meth, :$something! ) is export
{
say "METH : ", $meth.name;
}
}
# aaa.p6
use lib <.>;
use mmm;
class BBB is TTT {
method work is something { }
}
Output is: METH : work
But the same code gathered in the following unique file gives an error message
# bbb.p6
class TTT is export {
multi trait_mod:<is> (Routine $meth, :$something! ) is export
{
say "METH : ", $meth.name;
}
}
class BBB is TTT {
method work is something { }
}
Output is:
===SORRY!=== Error while compiling /home/home.mg6/yves/ygsrc/trait/bbb.p6
Can't use unknown trait 'is' -> 'something' in a method declaration.
at /home/home.mg6/yves/ygsrc/trait/bbb.p6:12
expecting any of:
rw raw hidden-from-backtrace hidden-from-USAGE pure default
DEPRECATED inlinable nodal prec equiv tighter looser assoc
leading_docs trailing_docs
I'm running this Rakudo version:
This is Rakudo Star version 2019.03.1 built on MoarVM version 2019.03
implementing Perl 6.d.
Why can't I run this code from a single file ?
What did I miss ?
According to the documentation:
Module contents (classes, subroutines, variables, etc.) can be
exported from a module with the is export trait; these are available
in the caller's namespace once the module has been imported with
import or use.
You can try using import to import the is trait into the current package:
bbb.p6:
module X { # <- declare a module name, e.g. 'X' so we can import it later..
class TTT is export {
multi trait_mod:<is> (Routine $meth, :$something! ) is export
{
say "METH : ", $meth.name;
}
}
}
import X;
class BBB is TTT {
method work is something { }
}