I have code that submits a POST request and returned are headers, body and a 200 status code. I assert on the status code to make sure it returned 200/204/302, then parse the response body and headers for data. I then assert on the returned value parsed from response headers/body and if that fails it changes the response status code to 409 in the NUnit test (even though it already asserted on it and passed because it was 200). Why is that and how do I fix this?
I am using the latest RestSharp and C# libraries. Running latest NUnit 3 version.
Calling my code and asserting on the parsed/returned data:
retvals = Common.restAPI(RestSharp.Method.Post, baseUrl, authEP, authType, get_cfg("CustomerApplication:procFinance:ep", new string[1] { "{app_id}" }, new string[1] { app_id }), get_cfg("CustomerApplication:procFinance:body", new string[2] { "{app_id}", "{amount}" }, new string[2] { app_id, amount.ToString() }), pid, new string[1] { "response.show_error" }, token: auth_token);
Assert.AreEqual("False", retvals[0]);
Code inside of the restAPI method I am calling:
/// <summary>
/// Main rest call method to execute a test.
/// </summary>
/// <param name="method">RestSharp.Method.Get, RestSharp.Method.Post, etc.</param>
/// <param name="baseUrl">The base URL of the API</param>
/// <param name="authRes">If authType is not AuthType.None, then this is used to authenticate before submitting the REST call.</param>
/// <param name="authType">Type of authentication used (New: Uses login/password and authRes to get bearer token and add it as an auth header, Old: Uses the getOldKey method and adds it as a 'x-api-key' header, Hash: Passes in an already generated bearer token and adds it as an auth header, None: No auth needed and authRes parameter is ignored)</param>
/// <param name="resource">The API endpoint under test</param>
/// <param name="body">[Optional] Body of the API endpoint to send</param>
/// <param name="pid">[Optional] PartnerID value to create requests, authType.Old authentication, etc.</param>
/// <param name="retval">[Optional] Values to search for and return from the response body and headers (searches body first and if value not found also searches headers). Can search in nested JObjects/JArrays by sending 'val1.val2' format. If no value passed, defaults to returning all headers and body via string array.</param>
/// <param name="username">[Optional] Used with authType.New for authentication</param>
/// <param name="password">[Optional] Used with authType.New for authentication</param>
/// <param name="token">[Optional] Used with authType.Hash for authentication</param>
/// <param name="status_code">[Optional] Default expected response status code is '200, 204, 302'. If you want to override this, send an alternate code</param>
/// <param name="headerNamePipeVal">[Optional] If a custom header is needed, send a string with header name and header value delimited with a '|' (myCustomHeader|myCustomHeaderValue)</param>
/// <param name="retvalAsserts">[Optional] If assertions need to be done within the RestAPI method, pass in the same size string array here compared with the retvals string array (if retvals has an array with size of 3 but only want to assert on the second item, pass in to retvalAsserts: new string[3] { "", "my value to assert", "" }).</param>
/// <returns>String array of values found from the retval parameter.</returns>
public string[] restAPI(Method method, string baseUrl, string authRes, AuthType authType, string resource, string body = "", string pid = "", string[] retval = null, string username = "", string password = "", string token = "", int status_code = 0, string headerNamePipeVal = "", string[] retvalAsserts = null)
{
string[] retvals = null;
//create new rest client instance
RestClient client = new RestClient();
//if 'New' or 'Hash' authType, this will add the appropriate bearer token header to the request
client = GetAuthClient(client, baseUrl, resource, authType, authRes, username, password, token);
//create the request with the resource point
RestRequest request = new RestRequest(resource);
if (authType == AuthType.Old)
{
request.AddHeader("x-api-token", GetXAPIKey(baseUrl, authRes, pid));
}
request.AddHeader("Accept", "*/*");
//add a custom header
if (headerNamePipeVal != "")
{
string[] head = headerNamePipeVal.Split("|");
request.AddHeader(head[0], head[1]);
}
switch (method)
{
case Method.Post:
//always add this header in case the request contains a jpg upload (so far, hasn't hurt any of the other post requests)
request.AddHeader("x-content-type", "image/jpg");
//add the post body
request.AddParameter("text/json", body, ParameterType.RequestBody);
break;
case Method.Put:
//always add this header in case the request contains a jpg upload (so far, hasn't hurt any of the other put requests)
request.AddHeader("x-content-type", "image/jpg");
//add the post body
request.AddParameter("text/json", body, ParameterType.RequestBody);
break;
}
TestContext.Out.WriteLine($"Request baseUrl: {baseUrl}");
TestContext.Out.WriteLine($"Request resource: {resource}");
TestContext.Out.WriteLine($"Request method: {method}");
TestContext.Out.WriteLine($"Request body: {body}");
TestContext.Out.WriteLine("");
//execute the request
RestResponse response = client.Execute(request, method);
TestContext.Out.WriteLine($"Response code: {(int)response.StatusCode}");
TestContext.Out.WriteLine($"Response code description: {response.StatusDescription}");
TestContext.Out.WriteLine($"Response status: {response.ResponseStatus}");
TestContext.Out.WriteLine($"Response headers: {JsonConvert.SerializeObject(response.Headers)}");
TestContext.Out.WriteLine($"Response body: {response.Content}");
TestContext.Out.WriteLine("");
//throw exception if both return values and return value assertions don't have the same length
if (retval != null && retvalAsserts != null)
{
if (retval.Length != retvalAsserts.Length)
{
throw new Exception("Return value count and return value assertion count need to match.");
}
}
Assert.Multiple(() =>
{
//verify return code is 200, 204 or 302 (OK, No Content or Redirect) if no return code specified, otherwise assert on the one specified
if (status_code == 0)
{
CollectionAssert.Contains(new[] { 200, 204, 302 }, (int)response.StatusCode);
}
else
{
Assert.AreEqual(status_code, (int)response.StatusCode);
}
int retvalAssertsCount = 0;
//parse out the specified return codes
retvals = parseResponse(response, retval);
//if both return values and return value assertions are not null, assert on each one that does not have a null return value assertion
if (retval != null && retvalAsserts != null)
{
foreach (string rv in retvals)
{
if (retvalAsserts[retvalAssertsCount] != "")
{
Assert.AreEqual(retvalAsserts[retvalAssertsCount], rv);
}
retvalAssertsCount++;
}
}
});
return retvals;
}
If the assertion passes written as 'Assert.AreEqual("False", retvals[0]);', it looks like this:

If I change the 'Assert.AreEqual("False", retvals[0]);' to 'Assert.AreEqual("True", retvals[0]);' so it fails, the response looks like this:

This is caused by the NUnit retry I have on the test. First failure is correct, but then it retries a second time and our AUT returns a 409 (which is correct).