I'm writing Spock + Geb based tests for web site testing. Web site is used to create offers and later various actions can be performed on them (confirm, reject, withdraw). I already created working scenario for creating an offer. But now when I came to the point that I need to implement scenarios for various combinations of actions I would like to be able to reuse "create offer" in these other scenarios. Unfortunately I'm not able to find any example or to think good way how to do it. Could someone give me any ideas about that?
By the way I need to perform actions in predefined sequence so I'm using Stepwise annotation on my specifications.
Single Page Actions:
It's hard to say without seeing examples of your code, but one way of doing this is to define the methods for your actions (confirm, reject, withdraw) as simple methods in your Page class:
class ActionsPage extends Page {
static content = {
//Page content here
}
def confirm (){
//Code to perform confirm action on the page
}
def reject (){
//Code to perform reject action on the page
}
Then in your Specification class you can do
def "Test confirm action"(){
when: "we go to the actions pages"
to ActionsPage
and: "we perform a confirm action"
confirm()
then: "something happens"
//Code which checks the confirmation worked
}
This works because Geb uses Groovy's method missing stuff to find the name of the method on the current page called "confirm ()", and will execute that code.
Multiple Page Actions:
If the actions are complicated and involve navigating to several pages, it is best to create an abstract base class for your tests which need to perform the actions:
//Not #Stepwise
abstract class BaseActionsSpec extends Specification {
//Note: don't use Spock when/then blocks in these methods as they are not feature methods
protected void confirm(){
//Code to perform multi-page action
}
protected void reject(){
//Code to perform multi-page action
}
}
Then the extending classes:
#Stepwise
class ConfirmActionSpec extends BaseActionsSpec{
def "Test confirm action"(){
when: "we go to the actions pages"
to ActionsPage
and: "we perform a confirm action"
confirm() //calls method in super class
then: "something happens"
//Code which checks the confirmation worked
}
}
Related
I have a weird problem with integration testing restful controllers... In the following code snippet, when I make a post request from tests, the save method of the parent, RestfulController class is called instead of the save method of the child class, MyController and because they have different signatures, this ends up resulting in a UNPROCESSIBLE_ENTITY response.
class MyController extends RestfulController<MyDomain> {
static responseFormats = ['json', 'xml', 'hal']
MyController() {
super(MyDomain)
}
def save(MyCommand command) {
...
}
}
When I run the following test, the save() action of my controller's parent class, RestfulController gets executed, thus leading to UNPROCESSIBLE_ENTITY response, since I am using a Command object which is different from my domain class.
void "Test the save action correctly persists an instance"() {
when: "The save action is executed with valid data"
response = restBuilder.post(resourcePath) {
accept('application/json')
header('Authorization', "Bearer ${accessToken}")
json validJson
}
then: "The response is correct"
response.status == CREATED.value()
response.json.id
Vote.count() == 1
}
What can I do to fix this, please?
Overloading controller actions is not supported. You can override them, but you can't overload them.
What is happening is the framework is invoking the no-arg save() action in the parent class, which never invokes your method (nor should it).
You can rename your save(MyCommand command) so it doesn't have the same name as an action in your parent class and then provide a corresponding URL mapping and you will be on your way. Depending on what you want to do in the action, that may or may not be the best thing, but that is 1 path you can take.
I hope that makes sense.
I've got REST webservice based on Grails. There's obligatory authentication before you can access any page except login.
I use Geb & Spock for integration tests, running through Gradle. My question is: how can I provide authentication before executing any test?
I have 2 ideas:
Run tests in order (log in at first, then run others). How? (must be triggering by command gradle integrationTest)
Execute JS script before every test which authenticate me. How to implement this in test?
What kind of authentication?
For Basic authentication have a look at:
HTTP Basic Authentication credentials passed in URL and encryption
so you could just add that to your base url.
If you have to go through the login process, you can use the setupSpec() and setup methods. The former gets executed before anything else happens, the latter before each individual test method.
You can use the #Stepwise notation to stop cookies from being deleted between test methods.
If you have different geb classes and want all of them to be prepended with your setup or setupSpec method, use the extends notation:
class BaseClass extends GebSpec {
def setupSpec() {
<loginProcess>
}
}
#Stepwise
class ASpec extends BaseClass {
testMethod() { }
}
#Stepwise
class BSpec extends BaseClass {
testMethod() { }
}
note that this will execute the login process one extra time because it happens in the BaseClass as well.
I got around this with an if (this.getClass().getPackage().getName() != "gebMethods") block but I guess there might be a more elegant solution.
If it's a web service I'd not use Geb for testing it. Geb is a tool for driving browsers and REST web services are best tested using http clients, like REST-assured.
I would make authentication configurable in the app and disable it for most tests apart from ones that explicitly test authentication.
With just simple following controller action spock integration-test. Here is my Test.
#Integration
#Rollback
class TestControllerSpec extends Specification {
def setup() {
}
def cleanup() {
}
void "test something"() {
setup:
def c = new TestController()
c.index()
expect:
c.response.contentType !=null
}
}
getting following Exception
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at grails.web.api.WebAttributes$Trait$Helper.currentRequestAttributes(WebAttributes.groovy:45)
at grails.web.api.ServletAttributes$Trait$Helper.getRequest(ServletAttributes.groovy:42)
I've been doing this and it seems to work fine:
Add field:
#Autowired
WebApplicationContext ctx
In setup():
GrailsWebMockUtil.bindMockWebRequest(ctx)
In cleanup():
RequestContextHolder.resetRequestAttributes()
Unfortunately it might be a limitation in Grails 3, that you cannot use integration tests to test controllers.
To integration test controllers it is recommended you use
create-functional-test command to create a Geb functional test.
Source from Grails documentation
This seems to be a major change of direction from previous versions of grails. If you really need to test a controller in an integration test, you could try doing this:
NOTE: I realize this might be a bad practice, and it goes against Grails documentation, but sometimes you also need to test things more programmatically, where unit tests aren't sufficient, and are Geb tests aren't granular enough.
#TestFor(TestController) // This will provide a mocked "controller" reference
#Integration
#Rollback
class TestControllerSpec extends Specification {
// If TestController uses any services, have them autowired into this test
#Autowired
SomeService someService
def setupSpec() {
// Now connect those services to the controller
controller.someService = someService
}
void "test something"() {
when:
controller.index()
then:
response.contentType != null
}
}
WARNING: After some additional work with this format I did find a problem. Using #TestFor will call Holders.clear() when it is complete, which means that there will not be a grailsApplication object in Holders. This will cause problems if you have any integration tests that run after one that uses the approach above. After much digging, it doesn't look like there is an easy (or even hard) way of making this work, which is possibly why it is not supported in Grails 3. That being said, one option is to mark other integration tests with #TestFor, so that the Holders class will be properly populated. Is this a hack? Yes it is! You will need to decide if it is worth the effort of adding this overhead to all tests. In my case it was only one other integration test that needed this (as it is a small application), but if it was more than that I would not use this approach.
I am using the Grails security plugin on a project. I am using the annotations on controller actions to restrict access to certain classes of users such as 'ROLE_ADMIN' or 'ROLE_USER'.
(using this as the basis for what I am doing: http://grails-plugins.github.com/grails-spring-security-core/docs/manual/guide/5%20Configuring%20Request%20Mappings%20to%20Secure%20URLs.html#5.1%20Defining%20Secured%20Annotations)
My question is, how do I restrict an action so a user can only see information about themselves. For instance, lets say I have a user with id = 1. If I have an action that shows information about the user at:
mySite/User/Show/1
how do I prevent that same user with id=1 from being able to access
mySite/User/Show/2
? Is there a simple way to do this?
You can also use Grails controller interceptor if you want to apply same logic to multiple actions
class SomeController {
def beforeInterceptor = [action: this.&checkUser ]
def springSecurityService
def checkUser() {
User user = User.get(params)
User logged = User.get(springSecurityService.principal.id)
if (user.id != logged.id) {
{
redirect(action: "accessDenied", controller='access' id: params.long("id")) //re-direct accessDenied page
return false
}
return true;
}
}
Class AccessController{
def accessDenied= {
render(view: "accessDenied")
}
}
What will be the problenm with the following?:
class SomeController {
springSecurityService
// other stuf ...
def show () {
User user = User.get(params)
User logged = User.get(springSecurityService.principal.id)
if (user.id != logged.id) {
flash.message = "You can't see the profile of other users"
redirect action:"list" // You can redirect to other controller/action
return //Since grails 2 this is needed
}
// Logic for display your user
}
// other stuf ...
}
what you are asking is part of your business rules. So you are supposed to take care of these scenarios in your code rather than looking out for some plugin or helper code.
What you can do for this is, make sure id of the user accessing the user details is same as id of the user whose details are being questioned.
You can also make this check at object level but that will mean an extra query to database to fetch the user details.
Hope this helps.
I have to agree that you are trying to implement a business rule with a security aspect. If a user created some kind of document, you would not use authorization to select what is visible on their profile page, would you?
You have to draw a line on where the authorization aspect reaches and where business rules start.
In my experience, to avoid blurring the lines, i always use authorization roles as types of users associated to a set of functionality. A specific user type can have access to a series of stories, or use cases. These use cases are constrained to specific roles.
If you start asking questions about data visibility (what is hidden on a page, depending on whatever business factor), then you should stay clear of your security framework
I would disagree that you need to redefine your business logic vs security logic. It is a common use case and authorization should cover it. This is why Grails has filters. Use an authorization filter to add functionality like this:
class AuthorizationFilters {
def filters = {
userCheck(controller: 'user', action: '*') {
before = {
// Check current user id is param.id here
}
}
}
}
Thus your security logic is outside your controller. You could add other controllers if they pass in a user id or even other methods that check if a domain class is owned by the current user here.
I have following controller structure:
abstract class AbstractController {
// ...
}
abstract class AbstractDiagramController extends AbstractController {
// ...
}
class PopulationController extends AbstractDiagramController {
// ...
}
Most controller-actions call various methods of the abstract base classes. If now one of these base-methods needs to send a redirect (or forward) to the client, Grails won't prevent the application from processing the remaining action code of the controller-action anyway.
From my point of view this is an undesirable behaviour, due the base-methods do some kind of validation (like validating parameter, user, session etc), and the controller assumes that the validation succeeded (thence produces subsequent errors).
How can i prevent this insufficient behaviour?
Kind regards,
Christopher
PS: I found already this question, but the answers did not satisfy my needs, because none of them deal with a base controller:
PPS: I am using Grails in version 1.3.7
EDIT
This is a reaction of Victor Sergienko's comments.
Here I give a more detailled code-example of my problem.
// The very base controller
abstract class AbstractController {
// The interceptor gets called before any action of inheritors get processed
def beforeInterceptor = [action:this.&initialize]
// Method validates various stuff
protected initialize() {
if( someThingIsWrong() ) {
// This redirect should stop any other code of inheritors
redirect( controller: "foo", action: "bar" )
return false
}
}
}
// The second base controller
abstract class AbstractDiagramController extends AbstractController {
// This object must get initialized. If not (eg any errors or exceptions occured)
// all inheritors actions are not allowed to do anything
MyObject myGreatObject = null
// Overriden, because of additional individual diagram validation
#Override
protected initialize() {
// Do parents stuff first
super.auth()
// If parent failed, this code should not get executed anymore.
// Yes, here I could check if parent returned false and return false as well before
// continuing the next validation. Anyway I have to do this because grails, comprehendibly,
// will throw an exception if two redirects were executed in a row.
// (With this I just want to visualize the behaviour I'd expect)
if( someThingElseIsWrong() ) {
redirect( controller: "hello", action: "world")
return false
}
// After validation I can initialize the object
myGreatObject = new MyObject()
}
}
// A controller implementation
class MyDiagramController extends AbstractDiagramController {
// Overriden because of inidividual validation
#Override
protected initialize() {
// First do parent stuff
boolean succeeded = super.auth()
// Again, annoying double check
if( !succeeded ) {
return false
}
}
def myAction = {
myGreatObject.SpinAroundAndBeHappy()
}
}
Looks like it was a good idea to reduce the use-case to the minimum lines of code. Now it seem like Victor's suggestions (either canContinue or hasErrors) could solve this unpleasant circumstances somehow, even though it's some kind of workaround.
But somehow I don't like those double-checks. I'm still struggling against the fact, that all layers above the abstract base controller have to react on invalid validations that happened already before (and also should be managed by the base controllers on their own). From my point of view those checks should not be the business of the controller implementations.
PS: I hope no grave mistakes have slipped in the code.
As a workaround, you can return a boolean canContinue from an ancestor action or throw an exception, or check instance.hasErrors() in your case.
EDIT: The fact initialize() is called before an action looks like access control or another complete override of action semantics (before any part of action is executed). Please tell if my assumption is wrong.
When we did a custom security access to different actions, we annotated the actions with own tags like #SecuredDoodah (see #Secured), and added a Filter that completely overrides the action (for us, Filter responds with 403, but it's not necessary).
Filter might be better than beforeInterceptor. If you need to pass some state from Filter, like myGreatObject in the sample, you can inject a Service into Filter and save the state in the Service.
I'm sure there are better ways then my idea, but this should work transparently for Controllers.
You're limited by the fact that this is Java/Groovy and there's no way for a method call to immediately trigger an exit from a method (or Closure). I saw that another framework cheats and when you call render, redirect, etc. it throws an exception that's caught it the framework base class. This acts like a Goto, which doesn't really exist.
It's an expensive approach though - filling in all those stack frames unnecessarily is wasteful since it's not an exception case and the stack will always be ignored.
Unfortunately you need an approach like Victor's where you use boolean return values.