I have a controller action that checks a condition and based on the condition's result, it will set a field to session variable
Controller:
def checkUser={
if(condition: true){
session.user = id
}else{
session.user=null
}
}
Now, in my testcase, if I have to assert on this session's user value, how do i do it?
I tried it like this, but it did not work:
void testSomething(){
controller.checkUser()
assertNull(session.user)
}
Any idea on how to assert session variable which is being set in the controller?
Make sure your test class extends ControllerUnitTestCase or is using the test Mixin.
CUTC offers several mocks to facilitate Controller testing. Here's what you'll do:
void testSomething(){
controller.checkUser()
assertNull(mockSession.user)
}
Here's the doc: http://grails.org/doc/1.3.x/api/grails/test/ControllerUnitTestCase.html
If you're using grails 2.0+: http://grails.org/doc/latest/api/grails/test/MvcUnitTestCase.html
Related
I use the Grails Spring Security Plugin for my project and now want to unit test my code. I have the following code in my controller:
def index() {
redirect action: 'show', params: [id: springSecurityService.currentUser.id]
}
My Test Class has the following code:
void testIndex() {
controller.index()
assert "/user/list" == response.redirectedUrl
}
This test fails:
| Running 8 unit tests... 1 of 8
| Failure: testIndex(xxx.UserControllerTests)
| java.lang.NullPointerException: Cannot get property 'currentUser' on null object
at xxx.UserController.index(UserController.groovy:12)
at xxx.UserControllerTests.testIndex(UserControllerTests.groovy:19)
How can I authenticate a spring security user in a test case? How would you write the unit test?
You have to use functional tests for security. Unit tests use mocking but don't have plugins available, or a real request. Spring Security is implemented with a filter chain, so you need a real running server. If you use mocks, you're just testing the mocking.
For something this simple I wouldn't bother with complicated mocks, a straightforward
controller.springSecurityService = [currentUser:[id:1]]
would be sufficient.
It appears that your reference to springSecurityService is null. As long as you have a field in your controller named springSecurityService, it should be injected. Are you using it as a local variable only in your index method and did not declare it as a field?
My UserController is as follows:
class UserController {
/**
* Dependency injection for the springSecurityService.
*/
def springSecurityService
....
}
UPDATE
Based on your comments to this answer, you did declare a springSecurityService field in your controller. I took my working application and tried a test that mirrors yours with my controller method:
#TestFor(UserController)
class UserControllerTests {
void testSomething() {
controller.register()
}
}
I got a NullPointerException as well. From Burt's answer, (I did not know this), I think the springSecurityService instance is null in the contexts of the Unit Test execution.
Is it possible to directly set a System.property for a particular method of a Grails unit test class?
I've got a Filters class that blocks some actions if a system property is set in Config.groovy:
class MyFilters {
def filters =
{
if ('true'.equals(System.properties.getProperty('myProperty', 'false'))){
writeFilter(controller: "myController", action: "update")
{
before =
{
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return false;
In MyControllerTests, I'm trying to implement a test for the filter:
void testMyFilter(){
System.properties.setProperty('myProperty', 'true')
withFilters(action:"update") {
controller.update()
}
assert response.status == HttpServletResponse.SC_FORBIDDEN
}
But the filter class is already mocked at this stage (using the default 'false' property value from Config) so the change of the property in the test has no effect.
Is there a way around this, or a way to force Grails to reload the Filters class after the prop is changed? I can't change the default property in Config as the other controller tests will break, it's just for a particular environment where this prop will be set so I'd like the scenario covered by a test that checks the Filter will kick in.
Thanks.
Inevitably, I found out how to do it about a minute after I posted this. Adding mockFilters(MyFilters) after the setProperty makes Grails rebuild the mocked filter with the updated property.
I am very new to Unit Testing, so I am starting on my first set of tests today. I am using the Library JustMock from Telerik. Though any unit testing information is good. I am having a bit of trouble with an interface service that passes through my method. Below is my MembershipController.Register(model) method...
[CaptchaValidator]
[HttpPost]
public ActionResult Register(Models.Membership.Registration model)
{
// just for good mesure, truncate any spaces that are given
System.Text.RegularExpressions.Regex.Replace(model.Email, #"\s", "");
if (ModelState.IsValid)
{
// Attempt to register the User and return any applicable status that has to do
// with the result.
var createStatus = membershipService.RegisterMember(model.Email, model.Password);
// if the member is able to be created successfully, log them in now and begin the
// authentication portion of the registration, otherwise, display the registration
// errors and return to the view.
if (createStatus == Membership.MemberCreateStatus.Success)
{
formsAuthentication.SignIn(model.Email, false /* createPersistentCookie */);
return RedirectToAction("Success");
}
else
{
ModelState.AddModelError("", Membership.Validator.ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
And here is the paltry test I am trying to run...
[TestMethod]
public void Register_Post_ReturnsRedirectOnSuccess()
{
// Arrange
var controller = Mock.Create<Web.Controllers.MembershipController>();
var repository = Mock.Create<Membership.IMembershipService>();
Mock.Arrange(() => repository.RegisterMember("acceptible#email.com", "acceptiblePassword")).Returns(Membership.MemberCreateStatus.Success);
// Model
var model = new Web.Models.Membership.Registration
{
Email = "acceptible#email.com",
Password = "acceptiblePassword",
ConfirmPassword = "acceptiblePassword"
};
// Act
var result = controller.Register(model);
// Assert
Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
}
The test fails because membershipService is resolving as null. I'm not sure what to do here. This is my first forray into the Unit Testing aspect of ASP.NET MVC. Can anyone give me some advice?
I am using Ninject to inject IMembershipService through the Constructor. It is implemented by the class MembershipService. The code runs fine when I run it, but the unit tests fail.
I don't see you passing repository anywhere into your controller. Normally you would have IMembershipService as a parameter in your controller's constructor that you can then pass in when needed or use MVC's Service Locator to grab the Ninject instance and pass it in.
:)
I have the following as my unit test:
void testCreateDealer() {
mockForConstraintsTests(Dealer)
def _dealer= new Dealer( dealerName:"ABC",
Email:"abc-motors#global.com",
HeadOffice:"",
isBranch:false)
assertFalse _dealer.validate()
}
But when I run the test I get the following error:
No signature of method: static com.myCompany.Dealer.findByDealerNameIlike() is applicable for argument types: (java.lang.String) values: [ABC]
I use some custom constraints in my domain class. How Can I test this?
static constraints = {
dealerName(blank:false, validator:
{ val, obj ->
def similarDealer = Dealer.findByDealerNameIlike(val)
return !similarDealer || (obj.id == similarDealer.id)
}
)
Try changing mockForConstraintsTests() to mockDomain() - you're using a Dealer.findX() method in the constraint, which relies on the Dealer domain.
Incidentally, the test will still fail unless you've created a similar dealer in the setUp() method of the test class.
In unit tests, even with mockDomain, the id attribute of domain objects is not set automatically, or auto-incremented. All of the domain objects you create will have an id of null unless you explicitly set it.
Your test is probably failing because the test obj.id == similarDealer.id is true, since they both have id: null. Try setting the id attribute of your mocked dealer objects.
I am trying to test a Controller
that has a Command object with data binding.
The Command Object has a Service injected into it.
But When I try test the command object the injected service method
is never found as it is never "injected"
Is there a way to mock a service inside a command object?
Test method
void testLoginPasswordInvalid() {
mockRequest.method = 'POST'
mockDomain(User, [new User(login:"freddy", password:"realpassword")])
mockLogging(UserService) // userService mocked
MockUtils.prepareForConstraintsTests(LoginCommand)
def userService = new UserService()
def user = userService.getUser("freddy")//Gets called and returns the mockDomain
assert userService.getUser("freddy")//Passes
def cmd = new LoginCommand(login:"freddy", password:"letmein")
cmd.validate() // Fails (userService is nevr injected)
controller.login(cmd)
assertTrue cmd.hasErrors()
assertEquals "user.password.invalid", cmd.errors.password
assertEquals "/store/index", renderArgs.view
}
The getUser() method of the userService isn't found
Cannot invoke method getUser() on null object
java.lang.NullPointerException: Cannot invoke method getUser() on null object
Code
The login method of the controller being called,
def login = { LoginCommand cmd ->
if(request.method == 'POST') {
if(!cmd.hasErrors()){
session.user = cmd.getUser()
redirect(controller:'store')
}
else{
render(view:'/store/index', model:[loginCmd:cmd])
}
}else{
render(view:'/store/index')
}
}
The Command Object has a "userService" injected into it.
The validator calls this userService to find a user
class LoginCommand {
def userService
String login
String password
static constraints = {
login blank:false, validator:{ val, cmd ->
if(!cmd.userService.getUser()){
return "user.not.found"
}
}
}
The userService.getUser() looks like this.
class UserService {
boolean transactional = true
User getUser(String login) {
return User.findByLogin(login)
}
}
Service injection is done using Spring autowire-by-name. (Grep the Grails source tree for autowire to find a nice code fragment you can use to get it to autowire your controllers for you in integration tests.) This only functions in integration tests, where there's a Spring application context around that has the beans that can be injected.
In unit tests, you have to do this yourself since there's no Spring-land surrounding your stuff. This can be a pain, but gives you some benefits:
1) It's easy to inject mock versions of services - for example, using an Expando - in order to more closely specify the behavior of your controller's collaborating services, and to allow you to test only the controller logic rather than the controller and service together. (You can certainly do the latter in a unit test as well, but you have the choice of how to wire it up.)
2) It forces you to be explicit about the dependencies of your controller - if you depend on it, your tests will show it. This makes them a better specification for the behavior of your controller.
3) You can mock only the pieces of external collaborators your controller depends on. This helps your tests be less fragile - less likely to need to change when things change.
Short answer: your test method needs a cmd.userService = userService line.
What John says is on the mark. One example might be:
def mockUsers = [new User(login:"freddy", password:"realpassword")]
mockDomain(User, mockUsers)
def userService = [getUser:{String login -> mockUsers[0]}] as UserService
def cmd = new LoginCommand (/*arguments*/)
cmd.userService = userService
You can lookup other ways to mock objects at http://groovy.codehaus.org/Groovy+Mocks