/// <summary> /// Creates a tester. /// </summary> public ConformanceApiTester(ConformanceApiTesterSettings settings) { _ = settings ?? throw new ArgumentNullException(nameof(settings)); m_tests = settings.Tests ?? throw new ArgumentException($"{nameof(settings.Tests)} is required.", nameof(settings)); m_api = settings.Api ?? throw new ArgumentException($"{nameof(settings.Api)} is required.", nameof(settings)); m_jsonSerializer = settings.JsonSerializer ?? throw new ArgumentException($"{nameof(settings.JsonSerializer)} is required.", nameof(settings)); m_httpClient = settings.HttpClient; var sameNameTests = m_tests.GroupBy(x => x.Test).FirstOrDefault(x => x.Count() != 1); if (sameNameTests != null) { throw new ArgumentException($"Multiple tests have the name {sameNameTests.First().Test}"); } foreach (var testsPerMethod in m_tests.GroupBy(x => x.Method).Select(x => x.ToList())) { for (var i = 0; i < testsPerMethod.Count; i++) { for (var j = i + 1; j < testsPerMethod.Count; j++) { if (ServiceObjectUtility.DeepEquals(testsPerMethod[i].Request, testsPerMethod[j].Request)) { throw new ArgumentException($"Tests must not have the same method name and request data, e.g. {testsPerMethod[i].Test} and {testsPerMethod[j].Test}."); } } } } }
private ServiceResult <T> Execute <T>(ServiceDto request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var methodName = Uncapitalize(request.GetType().Name.Substring(0, request.GetType().Name.Length - "RequestDto".Length)); var testsWithMethodName = m_tests.Where(x => x.Method == methodName).ToList(); if (testsWithMethodName.Count == 0) { return(ServiceResult.Failure(ServiceErrors.CreateInvalidRequest($"No tests found for method {methodName}."))); } var actualRequest = m_jsonSerializer.ToServiceObject(request); var testsWithMatchingRequest = testsWithMethodName.Where(x => ServiceObjectUtility.DeepEquals(x.Request, actualRequest)).ToList(); if (testsWithMatchingRequest.Count != 1) { return(ServiceResult.Failure(ServiceErrors.CreateInvalidRequest( $"{testsWithMatchingRequest.Count} of {testsWithMethodName.Count} tests for method {methodName} matched request: " + $"{m_jsonSerializer.ToJson(actualRequest)} ({string.Join(", ", testsWithMethodName.Select(x => m_jsonSerializer.ToJson(x.Request)))})"))); } var testInfo = testsWithMatchingRequest[0]; if (testInfo.Error != null) { var error = m_jsonSerializer.FromServiceObject <ServiceErrorDto>(testInfo.Error); var errorRoundTrip = m_jsonSerializer.ToServiceObject(error); if (!ServiceObjectUtility.DeepEquals(testInfo.Error, errorRoundTrip)) { return(ServiceResult.Failure(ServiceErrors.CreateInvalidRequest($"Error round trip failed for test {testInfo.Test}. expected={m_jsonSerializer.ToJson(testInfo.Error)} actual={m_jsonSerializer.ToJson(errorRoundTrip)}"))); } return(ServiceResult.Failure(error)); } else { var response = m_jsonSerializer.FromServiceObject <T>(testInfo.Response !); var responseRoundTrip = m_jsonSerializer.ToServiceObject(response); if (!ServiceObjectUtility.DeepEquals(testInfo.Response, responseRoundTrip)) { return(ServiceResult.Failure(ServiceErrors.CreateInvalidRequest($"Response round trip failed for test {testInfo.Test}. expected={m_jsonSerializer.ToJson(testInfo.Response)} actual={m_jsonSerializer.ToJson(responseRoundTrip)}"))); } return(ServiceResult.Success(response)); } }