Spock test in GEB cookies using where clause - cookies

I've configured some geb tests to check a different messages depending on the login attempt in my web app. Since the message and the input fields will change at the third login attempt.
The login is a two step login based on password send to a specific phone number, so in the first page LoginPage the user introduces their Id and phoneNumber, then it's redirected to the second page ValidationLoginPage where the user introduces the received password.
I want to check that in the second page the user can only introduces three bad passwords and at fourth attempt the input to introduce a password will disappear and a different message indicating that there are no more attempts it's showed.
To check this I prepared a test which introduces the Id and phoneNumber at the given: clause, and using where: clause it introduces a bad password three times. Since where: repeat all test I try to control the part to repeat using injected variable like in where: so I've something like:
def "Test max loging attempts"(){
given:
if(loginAttempt == 1)
to LoginPage
loginModule.startLogin(cfg.user.id,cfg.user.phone)
}
when:
at LoginValidationPage
assert $('div.box_id_header h3').text() == 'Verify your code'
assert $('#code').css('display').contains('block')
loginModule.verifyPassword('WRONGPASSWORD')
then:
at LoginValidationPage
println "Attempt ${loginAttempt}"
if(loginAttempt == 4){
// last attempt
assert $('#code').css('display') == 'none'
assert $('#divCodeErrorMsg').text().contains('No more attempts')
}else{
assert $('#code').css('display').contains('block')
assert $('#divCodeErrorMsg').text().contains('Wrong password. Try again.')
}
where:
loginAttempt << (1..4)
}
My problem is, that cookies are cleared for each where: iteration, thought the message and the behavior is not which I expect. I don't want to configure autoClearCookies=false in GebConfig.groovy file since I've another tests where this feature is necessary. There is a way to avoid the clear cookies for this method using spock def setupSpec() {} method and reactivate in def cleanupSpec() {} method?
Additionally it's also possible to use where: in a cleaner way avoiding to check the loginAttempt variable to avoid run given: part multiple times, or there is a better approach not using where: at all?

The problem is that you maybe misunderstand and thus abuse Spock's where: block. It is designed to parametrise a feature method and each run of that method comprises an independent feature. If you #Unroll your feature, even for each set of where: parameters a new method is generated. Because features should be independent of each other and theoretically be able run run in any given order or even in parallel, test fixtures need to be reset in order to run them. This is what happens with your cookies because you abuse the where: feature to implement a simple loop.
There are other little problems in your code, such as the non-asserted at check in the when: block. Even if at yields false, it has no consequence there if you do not use assert. You can only skip assert in then: or expect: blocks, but not in given: or when: and also not inside closures or helper methods which I will both use in my sample code.
How about this?
package de.scrum_master.stackoverflow.foo
import geb.spock.GebReportingSpec
class LoginTest extends GebReportingSpec {
def loginModule = new LoginModule()
def cfg = new Config()
def "Test max login attempts"() {
given: "we are at the login page"
browser.config.autoClearCookies = false
to LoginPage
when: "logging in 4x with wrong credentials"
(1..4).each {
loginWithWrongCredentials(it, it < 4)
}
then: "we get a 'no more attempts' error message"
$('#codi').css('display') == 'none'
$('#divCodiValidacioError').text().contains('No more attempts')
}
def loginWithWrongCredentials(int loginAttempt, boolean checkForWrongPasswordMessage) {
println "Login attempt ${loginAttempt}"
loginModule.startLogin(cfg.user.id, cfg.user.phone)
assert at(LoginValidationPage)
assert $('div.box_id_header h3').text() == 'Verify your code'
assert $('#code').css('display').contains('block')
loginModule.verifyPassword('WRONGPASSWORD')
assert at(LoginValidationPage)
if (checkForWrongPasswordMessage) {
assert $('#codi').css('display').contains('block')
assert $('#divCodiErrorMsg').text().contains('Wrong password. Try again.')
}
}
}
I would also recommend to move the content asserts from loginWithWrongCredentials into helper methods of LoginValidationPage where they rather belong and just call them from the test.

Finally disabling the autoClearCookies in the setup step I get the desired behavior.
def setup() {
browser.getConfig().setAutoClearCookies(false)
}
However surprisingly if I use setupSpec() method, seems that it not works, since only first where: iteration has autoClearCookies=false and the rest has autoClearCookies=true.

Related

How to do unit testing and how it is different from integration testing in frameworks like Django and fastapi?

Let's say I have a Fastapi application like this (This code is taken from documentations):
app = FastAPI()
#app.get("/foo")
async def read_main():
return {"msg": "Hello World"}
I believe there are two ways of testing this view. The first one is by the use of a client object. For instance:
client = TestClient(app)
def test_read_main():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"msg": "Hello World"}
However, I think this is not a unit test. It is more like an integration test. Because we are actually running fastapi codes as well.
The second option which in my opinion is closer to unit test definition is to run the function directly:
def test_read_main():
response = read_main()
assert response == {"msg": "Hello World"}
Similarly, in Django, we can directly call the view function, or by using a client object.
My first question is which one is better?
Let's say we chose one of them and now in order to prevent calling the database I have mocked the database. Now I want to test a view that just checks if something exists in the database. My second question is what is the point of testing such view? Becuase after mocking the database, we know what would happen when calling the database with given arguments.

Parametrized Spock test using #WithMockUser

I'd like to run a parametrized test in Spock using the #WithMockUser with a different role per each iteration.
As an example, the following test code shows no compilation error and is run twice.
But the result fails, since the #role is resolved only in the #Unroll, but not in the #WithMockUser annotation.
#Unroll("#role is authorized to get admin")
#WithMockUser(username = "user", roles = ["#role"])
def "User is authorized to get admin"() {
when:
def adminDto = adminController.getAdmin()
then:
adminDto.getStatusCode() == HttpStatus.OK
where:
role << ["USER", "ADMIN"]
}
So my question is: Is it possible to run such a test as a parametrized one?
Thank you in advance!
Note: I'm aware the annotation could look like:
#WithMockUser(username = "user", roles = ["USER", "ADMIN"])
but this would be a different behavior - one call with both roles.
Short answer no.
The annotations are statically compiled at compile time and cannot be modified by Spock, the iterations are generated/evaluated dynamically at runtime.
The #Unroll annotation has some special support for data variables to make it work, while the Spring annotation doesn't know anything about Spock.
You could look at WithMockUserSecurityContextFactory and use that to manually set the the SecurityContext in the given block.

How to test a function with N distinct paths?

I have a function which validates a model class where it has to check every member of the class to be non-null or non-empty in case of a String.
The logic for this is_complete function is something like this:
def is_complete(profile):
if profile.first_name in (None, ''):
return False
elif profile.last_name in (None, ''):
return False
elif profile.dob is None:
return False
.
.
.# and checks so on for all members of the profile instance
.
.
return True
My question since the number of possible paths the execution can take is quite large and increases in proportion to the number of member variables of profile to be checked, how does one reliably write tests for all the possible paths?
Right now, I have two simple test cases:
where only some of the members are set and checks assertFalse(is_complete(foo))
where all the members are set and checks assertTrue(is_complete(foo))
But I have a feeling that this may not be enough.
I'm not sure what you mean by having MxN paths. In the posted code you have as many paths as fields + 1.
Create a helper method that creates a profile that is complete and passes is_complete.
Add a test method to verify is_complete(profile) is True for the complete profile.
Add one test method for each field, with the following steps:
Call the helper method to create a complete profile that we know would pass is_complete
Break the field under test
Verify that is_complete returns False
You will have as many test methods as fields + 1.
Btw, instead of this:
if profile.first_name in (None, ''):
You can writer simpler:
if not profile.first_name:
You can test this with randomization:
Write a function that creates a random Profile object with all the fields filled (could be random, but valid).
Randomly change one or more fields to either None or empty
Pass the object to the is_complete() function.
I can show this only in Java with Qala Datagen. I assume you're interested in the negative paths, so it can look like this:
#Test void profileIsNotComplete_ifAtLeastOneFieldIsBlank() {
Profile p = Profile.random();
callOneOrMore(
() -> profile.setName(nullOrEmpty()),
() -> profile.setLastName(nullOrEmpty()),
...);
assertFalse(profile.isComplete();
}
Note, that this code actually tests more - it also checks the combination of fields set to null/empty. If in Python there are no such libs, you can write some utility methods for yourself.
NB: only one path is going to be tested per one execution. You can run it many times (a thousand?) to make sure that all the paths pass. Then in CI you can run it only once if this is not a mission-critical functionality and you're not afraid that it's going to break often.
Otherwise if you really want this to be covered 100% for every invocation, you can violate some of the good practices and just combine all these tests in one (otherwise there are going to be too many tests which complicate reading them):
#Test void profileIsNotComplete_ifOneFieldIsBlank() {
assertFalse(Profile.random().setName(null).isComplete());
assertFalse(Profile.random().setName("").isComplete());
assertFalse(Profile.random().setLastName(null).isComplete());
assertFalse(Profile.random().setLastName("").isComplete());
...
}
This doesn't test combinations though, but you can combine both approaches. The positive case is very easy in both approaches:
#Test void profileIsComplete_ifAllFieldsAreFilled() {
assertTrue(Profile.random());
}
More info on randomized testing is here.

How to mock get_current_user in tornado for unittest?

I have a tornado web application. Many pages require a valid cookie to access. It makes it impossible to test those handlers.
I want to use the mock library to mock the tornado.web.RequestHandler.get_current_user method. But I just cannot get right.
This is how I am doing right now:
class MyUT(tornado.testing.AsyncHTTPTestCase):
def get_app(self):
settings = {
"template_path": '../../../templates',
"cookie_secret": 'secret',
"login_url": '/admin/login',
"debug": True
}
return Application([
(r'/admin/create/super', handlers.CreateSuperUserHandler)
], **settings)
def testGet(self):
with mock.patch.object(handlers.CreateSuperUserHandler, 'get_current_user') as m:
m.return_value = {}
response = self.fetch('/admin/create/super')
print(response.body)
self.assertGreater(response.body.index('create'), 0)
If I execute this code, I got a 404 error. Because I did not define the login hanlder. But I am expecting the mocked get_current_user method return a user object, so do not go to the login page while testing.
One strange thing I found is, if I add m.assert_any_call() in the with block, there's no assertion error.
The #authenticated decorator redirects to the login page if get_current_user returns a falsy value. Try returning a non-empty dict.
You also use handlers.CreateSuperUserHandler in one place and handlers.AdminArea.CreateSuperUserHandler in another; are those the same class object?

Grails 2.1.x Controller Unit Testing with services

Attempting to unit test a Grails 2.1.x controller that calls a template to show a list of history items with a status. This controller works fine in manual testing but were attempting to automate things and I'm getting stuck on this part. Part of our issue may be that the domain object is over engineered.
The setup for this test may be more integration rather than unit testing but I'm not sure I can test the function with out it.
The controller action generates a list of history items via a createCriteria query. This list is passed to the template to be rendered.
def loadHistValues(){
def histDomainObject = new historyDom()
def elements = histDomainObject.createCriteria().list(max: params.max, offset: params.offset)
render (template: 'searchResults', model:[elements: elements]
}
The template has code that iterates through the list putting values in each column. One of these items is getStatus(). This calls a utility service to return the values.
def getStatus(){
return historyUtillityService.getStatus(this)
}
The service gets the latest history event and returns the value.
def getStatus(HistoryDom hist){
def histStatus = HistoryEvent.createCriteria().get(
maxResults(1)
order('id', 'desc')
eq('historyDom', hist)
)
if (histStatus == null)
return 0
else
return histStatus.status
}
I'm getting a null pointer when the getStatus() is called.
I've setup both mock domain object and mock services but I'm not sure that these are getting down to this level or maybe I'm calling them wrong.
#TestFor (HistoryController)
#MockFor (HistoryDom, HistoryEventDom)
class HistoryControllerTests{
def util = new UnitTestUtil()
void testLoadHistValues(){
def mockHistoryUtilityService = mockfor (HistoryUtilityService)
mockHisotryUtilityService.demand.getStatus (-> return Status.QUEUED)
def histObj1 = util.initMockHistObj(1)
def histObj2 = util.initMockHistObj(2)
histObj1.save()
histObj2.save()
def mockHistEvent = new HistEvent(
histDate: histObj1.getHistDate(),
histObj: histObj1,
histStatus: Status.QUEUED
)
mockHistEvent.save()
controller.loadHistValues()
assert response.text contains("Something worth testing")
}
I tried setting a mock view before the call to the controller and checking the response text for that but it never gets past the call to the controller since its still trying to process the template. I'm at a loss at this point as to how to test this controller function, or is it that the object wasn’t architected properly; this seems a bit overly complicated.
answer was to mock things for constrainsts tests before they would get fully saved by mock GORM. I guess mockForConstraintsTests dosnt quite function as I expected