├── CourseLandingPage.png
├── README.md
├── pom.xml
└── src
└── test
├── java
└── com
│ └── spotify
│ └── oauth2
│ ├── api
│ ├── RestResource.java
│ ├── Route.java
│ ├── SpecBuilder.java
│ ├── StatusCode.java
│ ├── TokenManager.java
│ └── applicationApi
│ │ └── PlaylistApi.java
│ ├── pojo
│ ├── Error.java
│ ├── ExternalUrls.java
│ ├── ExternalUrls_.java
│ ├── Followers.java
│ ├── InnerError.java
│ ├── Owner.java
│ ├── Playlist.java
│ └── Tracks.java
│ ├── tests
│ ├── BaseTest.java
│ └── PlaylistTests.java
│ └── utils
│ ├── ConfigLoader.java
│ ├── DataLoader.java
│ ├── DummyClass.java
│ ├── FakerUtils.java
│ └── PropertyUtils.java
└── resources
├── allure.properties
├── config.properties
└── data.properties
/CourseLandingPage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/omprakashchavan01/RestAssuredTestNGFramework/d8c92d59c5fbdd52a9fe46193efe3225128e25d8/CourseLandingPage.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RestAssuredTestNGFramework
2 | REST Assured API test automation framework using Java + Maven + TestNG.
3 | Framework follows many of the industry best practices.
4 |
5 | **Step by step instructions to build this framework from scratch and integrate with Jenkins CI is in this Highest Rated Udemy course.
6 | Enroll today at the minimal rate of INR 499/ $14.99.
7 | Link with coupon code: https://www.udemy.com/course/rest-assured-api-automation/?couponCode=APR2024**
8 |
9 | 
10 |
11 | Technologies/Tools used in building the framework
12 | =================================================
13 | - Rest Assured
14 | - TestNG
15 | - Java
16 | - Allure Reports
17 | - Hamcrest
18 | - Jackson API
19 | - Lombok
20 | - IntelliJ
21 | - GitHub
22 | - Jenkins
23 |
24 | Framework implements below best practices
25 | =========================================
26 | - Scalable and extensible
27 | - Reusable Rest Assured specifications
28 | - Reusable Rest Assured API requests
29 | - Separation of API layer from test layer
30 | - POJOs for Serialization and Deserialization
31 | - Singleton Design Pattern
32 | - Lombok for reducing Boilerplate code
33 | - Builder pattern for Setter methods in POJOs
34 | - Robust reporting and logging using Allure
35 | - Automate positive and negative scenarios
36 | - Support parallel execution
37 | - Data driven using TestNG Data Provider
38 | - Automated access token renewal
39 | - Maven command line execution
40 | - Integration with Git
41 | - Integration with Jenkins
42 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | RestAssuredFramework
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 1.9.20.1
13 |
14 |
15 |
16 |
17 |
18 | org.apache.maven.plugins
19 | maven-compiler-plugin
20 |
21 | 21
22 | 21
23 |
24 |
25 |
26 | org.apache.maven.plugins
27 | maven-surefire-plugin
28 | 3.2.2
29 |
30 | methods
31 | 10
32 |
33 | -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
34 |
35 |
36 |
37 |
38 | org.aspectj
39 | aspectjweaver
40 | ${aspectj.version}
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | io.rest-assured
51 | rest-assured
52 | 5.3.2
53 | test
54 |
55 |
56 |
57 | org.testng
58 | testng
59 | 7.8.0
60 | test
61 |
62 |
63 |
64 | com.fasterxml.jackson.core
65 | jackson-databind
66 | 2.15.3
67 |
68 |
69 |
70 | org.skyscreamer
71 | jsonassert
72 | 1.5.1
73 | test
74 |
75 |
76 |
77 | org.projectlombok
78 | lombok
79 | 1.18.30
80 | provided
81 |
82 |
83 |
84 | io.qameta.allure
85 | allure-testng
86 | 2.24.0
87 |
88 |
89 |
90 | io.qameta.allure
91 | allure-rest-assured
92 | 2.24.0
93 |
94 |
95 |
96 | com.github.javafaker
97 | javafaker
98 | 1.0.2
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/api/RestResource.java:
--------------------------------------------------------------------------------
1 | package com.spotify.oauth2.api;
2 |
3 | import io.restassured.response.Response;
4 |
5 | import java.util.HashMap;
6 |
7 | import static com.spotify.oauth2.api.Route.API;
8 | import static com.spotify.oauth2.api.Route.TOKEN;
9 | import static com.spotify.oauth2.api.SpecBuilder.*;
10 | import static io.restassured.RestAssured.given;
11 |
12 | public class RestResource {
13 |
14 | public static Response post(String path, String token, Object requestPlaylist){
15 | return given(getRequestSpec()).
16 | body(requestPlaylist).
17 | auth().oauth2(token).
18 | when().post(path).
19 | then().spec(getResponseSpec()).
20 | extract().
21 | response();
22 | }
23 |
24 | public static Response postAccount(HashMap formParams){
25 | return given(getAccountRequestSpec()).
26 | formParams(formParams).
27 | when().post(API + TOKEN).
28 | then().spec(getResponseSpec()).
29 | extract().
30 | response();
31 | }
32 |
33 | public static Response get(String path, String token){
34 | return given(getRequestSpec()).
35 | auth().oauth2(token).
36 | when().get(path).
37 | then().spec(getResponseSpec()).
38 | extract().
39 | response();
40 | }
41 |
42 | public static Response update(String path, String token, Object requestPlaylist){
43 | return given(getRequestSpec()).
44 | auth().oauth2(token).
45 | body(requestPlaylist).
46 | when().put(path).
47 | then().spec(getResponseSpec()).
48 | extract().
49 | response();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/api/Route.java:
--------------------------------------------------------------------------------
1 | package com.spotify.oauth2.api;
2 |
3 | public class Route {
4 | public static final String BASE_PATH = "/v1";
5 | public static final String API = "/api";
6 | public static final String TOKEN = "/token";
7 | public static final String USERS = "/users";
8 | public static final String PLAYLISTS = "/playlists";
9 | }
10 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/api/SpecBuilder.java:
--------------------------------------------------------------------------------
1 | package com.spotify.oauth2.api;
2 |
3 | import io.qameta.allure.restassured.AllureRestAssured;
4 | import io.restassured.builder.RequestSpecBuilder;
5 | import io.restassured.builder.ResponseSpecBuilder;
6 | import io.restassured.filter.log.LogDetail;
7 | import io.restassured.http.ContentType;
8 | import io.restassured.specification.RequestSpecification;
9 | import io.restassured.specification.ResponseSpecification;
10 |
11 | import static com.spotify.oauth2.api.Route.BASE_PATH;
12 |
13 | public class SpecBuilder {
14 |
15 | public static RequestSpecification getRequestSpec(){
16 | return new RequestSpecBuilder().
17 | setBaseUri(System.getProperty("BASE_URI")).
18 | // setBaseUri("https://api.spotify.com").
19 | setBasePath(BASE_PATH).
20 | setContentType(ContentType.JSON).
21 | addFilter(new AllureRestAssured()).
22 | log(LogDetail.ALL).
23 | build();
24 | }
25 |
26 | public static RequestSpecification getAccountRequestSpec(){
27 | return new RequestSpecBuilder().
28 | setBaseUri(System.getProperty("ACCOUNT_BASE_URI")).
29 | // setBaseUri("https://accounts.spotify.com").
30 | setContentType(ContentType.URLENC).
31 | addFilter(new AllureRestAssured()).
32 | log(LogDetail.ALL).
33 | build();
34 | }
35 |
36 | public static ResponseSpecification getResponseSpec(){
37 | return new ResponseSpecBuilder().
38 | log(LogDetail.ALL).
39 | build();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/api/StatusCode.java:
--------------------------------------------------------------------------------
1 | package com.spotify.oauth2.api;
2 |
3 | public enum StatusCode {
4 | CODE_200(200, ""),
5 | CODE_201(201, ""),
6 | CODE_400(400, "Missing required field: name"),
7 | CODE_401(401, "Invalid access token");
8 |
9 | public final int code;
10 | public final String msg;
11 |
12 | StatusCode(int code, String msg) {
13 | this.code = code;
14 | this.msg = msg;
15 | }
16 |
17 | /* public int getCode(){
18 | return code;
19 | }
20 |
21 | public String getMsg(){
22 | return msg;
23 | }*/
24 | }
25 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/api/TokenManager.java:
--------------------------------------------------------------------------------
1 | package com.spotify.oauth2.api;
2 |
3 | import com.spotify.oauth2.utils.ConfigLoader;
4 | import io.restassured.response.Response;
5 |
6 | import java.time.Instant;
7 | import java.util.HashMap;
8 |
9 | public class TokenManager {
10 | private static String access_token;
11 | private static Instant expiry_time;
12 |
13 | public synchronized static String getToken(){
14 | try{
15 | if(access_token == null || Instant.now().isAfter(expiry_time)){
16 | System.out.println("Renewing token ...");
17 | Response response = renewToken();
18 | access_token = response.path("access_token");
19 | int expiryDurationInSeconds = response.path("expires_in");
20 | expiry_time = Instant.now().plusSeconds(expiryDurationInSeconds - 300);
21 | } else{
22 | System.out.println("Token is good to use");
23 | }
24 | }
25 | catch (Exception e){
26 | e.printStackTrace();
27 | throw new RuntimeException("ABORT!!! Failed to get token");
28 | }
29 | return access_token;
30 | }
31 |
32 | private static Response renewToken(){
33 | HashMap formParams = new HashMap();
34 | formParams.put("client_id", ConfigLoader.getInstance().getClientId());
35 | formParams.put("client_secret", ConfigLoader.getInstance().getClientSecret());
36 | formParams.put("refresh_token", ConfigLoader.getInstance().getRefreshToken());
37 | formParams.put("grant_type", ConfigLoader.getInstance().getGrantType());
38 |
39 | Response response = RestResource.postAccount(formParams);
40 |
41 | if(response.statusCode() != 200){
42 | throw new RuntimeException("ABORT!!! Renew Token failed");
43 | }
44 | return response;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/api/applicationApi/PlaylistApi.java:
--------------------------------------------------------------------------------
1 | package com.spotify.oauth2.api.applicationApi;
2 |
3 | import com.spotify.oauth2.api.RestResource;
4 | import com.spotify.oauth2.pojo.Playlist;
5 | import com.spotify.oauth2.utils.ConfigLoader;
6 | import io.qameta.allure.Step;
7 | import io.restassured.response.Response;
8 |
9 | import static com.spotify.oauth2.api.Route.PLAYLISTS;
10 | import static com.spotify.oauth2.api.Route.USERS;
11 | import static com.spotify.oauth2.api.TokenManager.getToken;
12 |
13 | public class PlaylistApi {
14 |
15 | @Step
16 | public static Response post(Playlist requestPlaylist){
17 | return RestResource.post(USERS + "/" + ConfigLoader.getInstance().getUser()
18 | + PLAYLISTS, getToken(), requestPlaylist);
19 | }
20 |
21 | public static Response post(String token, Playlist requestPlaylist){
22 | return RestResource.post(USERS + "/" + ConfigLoader.getInstance().getUser()
23 | + PLAYLISTS, token, requestPlaylist);
24 | }
25 |
26 | public static Response get(String playlistId){
27 | return RestResource.get(PLAYLISTS + "/" + playlistId, getToken());
28 | }
29 |
30 | public static Response update(String playlistId, Playlist requestPlaylist){
31 | return RestResource.update(PLAYLISTS + "/" + playlistId, getToken(), requestPlaylist);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/pojo/Error.java:
--------------------------------------------------------------------------------
1 | package com.spotify.oauth2.pojo;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import lombok.Builder;
6 | import lombok.Getter;
7 | import lombok.Setter;
8 | import lombok.extern.jackson.Jacksonized;
9 |
10 | @Getter @Setter
11 | @Jacksonized
12 | @Builder
13 | @JsonInclude(JsonInclude.Include.NON_NULL)
14 | public class Error {
15 |
16 | @JsonProperty("error")
17 | private InnerError error;
18 | }
19 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/pojo/ExternalUrls.java:
--------------------------------------------------------------------------------
1 |
2 | package com.spotify.oauth2.pojo;
3 |
4 | import com.fasterxml.jackson.annotation.JsonInclude;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 |
7 | @JsonInclude(JsonInclude.Include.NON_NULL)
8 | public class ExternalUrls {
9 |
10 | @JsonProperty("spotify")
11 | private String spotify;
12 |
13 | @JsonProperty("spotify")
14 | public String getSpotify() {
15 | return spotify;
16 | }
17 |
18 | @JsonProperty("spotify")
19 | public void setSpotify(String spotify) {
20 | this.spotify = spotify;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/pojo/ExternalUrls_.java:
--------------------------------------------------------------------------------
1 |
2 | package com.spotify.oauth2.pojo;
3 |
4 | import com.fasterxml.jackson.annotation.JsonInclude;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 |
7 | @JsonInclude(JsonInclude.Include.NON_NULL)
8 | public class ExternalUrls_ {
9 |
10 | @JsonProperty("spotify")
11 | private String spotify;
12 |
13 | @JsonProperty("spotify")
14 | public String getSpotify() {
15 | return spotify;
16 | }
17 |
18 | @JsonProperty("spotify")
19 | public void setSpotify(String spotify) {
20 | this.spotify = spotify;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/pojo/Followers.java:
--------------------------------------------------------------------------------
1 |
2 | package com.spotify.oauth2.pojo;
3 |
4 | import com.fasterxml.jackson.annotation.JsonInclude;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 |
7 | @JsonInclude(JsonInclude.Include.NON_NULL)
8 | public class Followers {
9 |
10 | @JsonProperty("href")
11 | private Object href;
12 | @JsonProperty("total")
13 | private Integer total;
14 |
15 | @JsonProperty("href")
16 | public Object getHref() {
17 | return href;
18 | }
19 |
20 | @JsonProperty("href")
21 | public void setHref(Object href) {
22 | this.href = href;
23 | }
24 |
25 | @JsonProperty("total")
26 | public Integer getTotal() {
27 | return total;
28 | }
29 |
30 | @JsonProperty("total")
31 | public void setTotal(Integer total) {
32 | this.total = total;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/pojo/InnerError.java:
--------------------------------------------------------------------------------
1 | package com.spotify.oauth2.pojo;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | @JsonInclude(JsonInclude.Include.NON_NULL)
7 | public class InnerError {
8 |
9 | @JsonProperty("status")
10 | private Integer status;
11 | @JsonProperty("message")
12 | private String message;
13 |
14 | @JsonProperty("status")
15 | public Integer getStatus() {
16 | return status;
17 | }
18 |
19 | @JsonProperty("status")
20 | public void setStatus(Integer status) {
21 | this.status = status;
22 | }
23 |
24 | @JsonProperty("message")
25 | public String getMessage() {
26 | return message;
27 | }
28 |
29 | @JsonProperty("message")
30 | public void setMessage(String message) {
31 | this.message = message;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/pojo/Owner.java:
--------------------------------------------------------------------------------
1 |
2 | package com.spotify.oauth2.pojo;
3 |
4 | import com.fasterxml.jackson.annotation.JsonInclude;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 |
7 | @JsonInclude(JsonInclude.Include.NON_NULL)
8 | public class Owner {
9 |
10 | @JsonProperty("display_name")
11 | private String displayName;
12 | @JsonProperty("external_urls")
13 | private ExternalUrls_ externalUrls;
14 | @JsonProperty("href")
15 | private String href;
16 | @JsonProperty("id")
17 | private String id;
18 | @JsonProperty("type")
19 | private String type;
20 | @JsonProperty("uri")
21 | private String uri;
22 |
23 | @JsonProperty("display_name")
24 | public String getDisplayName() {
25 | return displayName;
26 | }
27 |
28 | @JsonProperty("display_name")
29 | public void setDisplayName(String displayName) {
30 | this.displayName = displayName;
31 | }
32 |
33 | @JsonProperty("external_urls")
34 | public ExternalUrls_ getExternalUrls() {
35 | return externalUrls;
36 | }
37 |
38 | @JsonProperty("external_urls")
39 | public void setExternalUrls(ExternalUrls_ externalUrls) {
40 | this.externalUrls = externalUrls;
41 | }
42 |
43 | @JsonProperty("href")
44 | public String getHref() {
45 | return href;
46 | }
47 |
48 | @JsonProperty("href")
49 | public void setHref(String href) {
50 | this.href = href;
51 | }
52 |
53 | @JsonProperty("id")
54 | public String getId() {
55 | return id;
56 | }
57 |
58 | @JsonProperty("id")
59 | public void setId(String id) {
60 | this.id = id;
61 | }
62 |
63 | @JsonProperty("type")
64 | public String getType() {
65 | return type;
66 | }
67 |
68 | @JsonProperty("type")
69 | public void setType(String type) {
70 | this.type = type;
71 | }
72 |
73 | @JsonProperty("uri")
74 | public String getUri() {
75 | return uri;
76 | }
77 |
78 | @JsonProperty("uri")
79 | public void setUri(String uri) {
80 | this.uri = uri;
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/test/java/com/spotify/oauth2/pojo/Playlist.java:
--------------------------------------------------------------------------------
1 |
2 | package com.spotify.oauth2.pojo;
3 |
4 | import com.fasterxml.jackson.annotation.JsonInclude;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import lombok.Builder;
7 | import lombok.Value;
8 | import lombok.extern.jackson.Jacksonized;
9 |
10 | import java.util.List;
11 |
12 | @Value
13 | //@Data
14 | //@Getter @Setter
15 | @Jacksonized
16 | @Builder
17 | @JsonInclude(JsonInclude.Include.NON_NULL)
18 | public class Playlist {
19 | @JsonProperty("collaborative")
20 | Boolean collaborative;
21 | @JsonProperty("description")
22 | String description;
23 | @JsonProperty("external_urls")
24 | ExternalUrls externalUrls;
25 | @JsonProperty("followers")
26 | Followers followers;
27 | @JsonProperty("href")
28 | String href;
29 | @JsonProperty("id")
30 | String id;
31 | @JsonProperty("images")
32 | List