Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factorization Serenity response in validator class and fluent annotation #1863

Closed
krys86 opened this issue Nov 4, 2019 · 8 comments
Closed
Labels

Comments

@krys86
Copy link

krys86 commented Nov 4, 2019

Hello

To perform validation check on the response of our API, we created the various steps we need:

responseValidator.checkStatusCode(response, Status.CREATED);
responseValidator.checkResponseField(response, ID_FIELD, VALID_COLLECTION_ID);
responseValidator.checkResponseField(response, DOCUMENTS_FIELD, Collections.emptyList());

The problem is we are obliged to pass the response in the method every time, which makes the code heavy and forces us to rewrite each step description to remove it.

Would it be possible to pass the response to the validator and perform the check without passing it to every method?
We have in mind something like this:

responseValidator = validator.onResponse(response)
responseValidator.checkStatusCode(Status.CREATED);
responseValidator.checkField(ID_FIELD, VALID_COLLECTION_ID);
responseValidator.checkField(DOCUMENTS_FIELD, Collections.emptyList());

This way the response is provided once and the steps description can build on the method name and arguments.

Moreover, checking the documentation, I saw there is a "fluent" attribute for the "Step" annotation but there is no doc at all about its meaning. Could it help?

Thanks in advance

@wakaleo
Copy link
Member

wakaleo commented Nov 4, 2019

You can use SerenityRest.lastResponse(). But I would just use a custom-made class that takes a ValidatableResponse object in the constructor and use soft asserts. The "fluent" attribute is not currently active.

@krys86 krys86 closed this as completed Nov 5, 2019
@krys86 krys86 reopened this Nov 5, 2019
@matthieu-vergne
Copy link

Hi,

I am with @krys86 on that issue.

The point is that we already use the ValidatableResponse. The checkStatusCode(...) method takes a Response and execute response.then().statusCode(...).

Our issue is to have a fluent design but which preserves the steps definitions, to make them appear in the report. The ValidatableResponse does not do that, so we put it in our custom method on which a @Step annotation is defined.

Our question is how to redesign our custom methods in a fluent manner without loosing them in the report?

@wakaleo
Copy link
Member

wakaleo commented Nov 5, 2019

Have you considered a builder pattern that uses a fluent interface to prepare the API call, and then makes the call with a @step method at the end? That’s how it works with Screenplay.

@matthieu-vergne
Copy link

If we use a single builder instance, we lack in code correctness: one can call the end method without calling the 'onResponse(...)'. Moreover, it becomes interesting for a SOLID design bexause we can have a single Validator, from which we can obtain a ResponseValidator with 'onResponse(response)', an EnvironmentValidatoe with 'onEnv()', which allows us to create different classes for different types of validations. But this design requires to generate a ResponseValidator instance on the fly, but still consider it as a source of Steps to retrieve in the report. So far we were unable to keep them in the report with the new instance.

@wakaleo
Copy link
Member

wakaleo commented Nov 5, 2019

That will be hard to do using step library class.

@matthieu-vergne
Copy link

But this is the goal.

We use Serenity since only recently, so we are far from mastering it, so maybe you can pinpoint us on some wrong ways we are going.

So far, we are forced to use a @Steps annotation on a field, so we must create a new class for any specific set of new steps we want to define. We cannot create a method next to a test, annotate it with @Step, and use it to feed the report. This is like JUnit 4 parameterized tests: it was heavy to use and thus not motivating. JUnit 5 did a great job by simplifying it. Similarly, by needing only the @Step annotation we may have defined a fluent interface with only the last method having the annotation.

The other limitation is that we must keep the @Steps-annotated field uninstantiated, in order to let the framework instantiate it as a single instance. This is extremely restrictive because we cannot have different instances for different contexts (e.g. each test its own response, so its own ResponseValidator).

Is there some other ways to go which could help us adapt the design of our classes without losing the reporting?

@wakaleo
Copy link
Member

wakaleo commented Nov 6, 2019

If you use the Screenplay pattern you will have more flexibility about how you create your classes and methods.

@matthieu-vergne
Copy link

I read a post about how to use the Screenplay of Serenity in Java:
http://testerstories.com/2016/06/screenplay-pattern-with-java-part-1/

Honestly, I am not convinced about it at all. I find it far too heavy given our simple case.

However, it gave me the right hints with the instrumented classes. More precisely, I import your Instrumented class:

import net.serenitybdd.core.steps.Instrumented;

It allows me to instrument my instance, although I need to feed it after instanciation but that's OK:

private Response response;

public static ResponseValidator on(Response response) {
    final ResponseValidator validator = Instrumented.instanceOf(ResponseValidator.class).newInstance();
    validator.response = response;
    return validator;
}

This way, I can have a fluent design:

ResponseValidator.on(response).checkStatus(Status.OK);

I can then reuse that in a more global Validator class or whatever without needing @Steps but still having it in the report.

We will experiment on that. Thank you.

@wakaleo wakaleo closed this as completed Feb 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants