0

请原谅我的无知,因为我是一个相当新的程序员,更不用说测试员了,我的问题涉及我组织中 API 的测试。我的任务是执行集成测试,确保我们在 Web 应用程序中使用的 API 调用返回正确的 HTTP 状态代码。在某些情况下,我还确认 API 实际上已将数据输入数据库。我正在使用 MSTest 通过 Visual Studio Integrated Test Runner 运行我的测试。目标是有一套测试,我们可以在每晚的基础上运行我们的 drop。

继续....

我正在使用的示例处理多个 PatronMessage api 调用。

该系统能够

  1. 返回系统定义的消息列表
  2. 返回读者特定消息的列表
  3. 向读者添加新消息
  4. 修改读者消息
  5. 删除读者消息

我编写代码的方式是,我有一个 xml 文件,其中包含属性 apiObject(PatronMessages) 和 objectAction(GetSystemDefined-Successful) 以及其他属性,但这些用于测试识别目的。

我还有一个名为 TestCase 的抽象类,它有几个实现的、虚拟的和抽象的方法。然后我创建了一个 PatronMessagesTestCase 类,它扩展了 TestCase 并实现了所有抽象并覆盖了 TestCase 中的一些虚拟方法。然后将来自 TestCase 的 RunTest 具体方法传递给 apiObject 和 objectAction 并从 xml 文件返回测试参数以运行测试。此 RunTest 方法返回一个布尔值,指示测试是否通过。

我遇到的问题是大多数测试的验证方式完全不同。我有一个 MakeDatabaseCall 方法,它在 PatronMessagesTestCase 中实现了 TestCase 的抽象方法,但是这个 MakeDatabaseCall 可能不同,也可能不同。例如:

为了测试添加新消息,我将检查数据库值以获得最高消息 ID,然后执行 api 调用,然后检查数据库值并确认调用后的消息 ID 更大。虽然对于删除消息测试,我可能会运行相同的测试,但检查数据库值是否低于先前检查的值。

我知道我可以添加一个开关并打开 objectAction,但是我的 PatronMessagesTestCase 中的每个方法都需要打开 objectAction,这对我来说似乎是错误的。

再一次继续前进…………

所以昨天我向一位高级开发人员寻求帮助,他建议我使用一个接口(ITestCase)来构造一个测试用例,然后有一个实现 ITestCase 的类(PatronAssociationsTestCase)并创建一个运行所有测试用例的测试运行器类但我做了一点,我有点困惑这将如何帮助我的情况(我真的认为它只会让情况变得更糟。但这是我的代码,请记住,我几乎试图两次完成同样的事情, 只是在两个不同的地方以两种不同的方式。另外请记住,这不是完整的代码,所以它可能会引发一些错误(我开始工作并且有点卡在我的想法上)......

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LEAPIntegrationTestingFINAL
{
    public interface ITestCase
    {
        public Dictionary<string, object> GetTestParams(string apiObject, string     objectAction);
        public string ConfigureURL(string objectAction);
        //public Dictionary<string, object> ConfigureRequestBody(Dictionary<string,     object> testParams); //<=-=-=-Some tests need to 
        public Dictionary<string, object> ExecuteRequest(Dictionary<string, object>     testParams);
        public Dictionary<string, object> ParseResponse(Dictionary<string, object>    responseValues);
         //public Dictionary<string, object> MakeDatabaseCall(Dictionary<string, object> testParams); //<=-=-=-Some tests need to
        public bool CompareData(Dictionary<string, object> databaseValues,    Dictionary<string, object> responseValues);
   }

public static class TestRunner 
{
    public static bool RunTest(ITestCase TestCase, string apiObject, string objectAction) 
    {
        bool comparisonValue = false;
        return comparisonValue;
    }
}

public class PatronAssociationsTestCase : ITestCase 
{

    public Dictionary<string, object> GetTestParams(string apiObject, string objectAction)
    {
        throw new NotImplementedException();
    }

    public string ConfigureURL(string objectAction)
    {
        throw new NotImplementedException();
    }

    public Dictionary<string, object> ConfigureRequestBody(Dictionary<string, object> testParams)
    {
        throw new NotImplementedException();
    }

    public Dictionary<string, object> ExecuteRequest(Dictionary<string, object> testParams)
    {
        throw new NotImplementedException();
    }

    public Dictionary<string, object> ParseResponse(Dictionary<string, object> responseValues)
    {
        throw new NotImplementedException();
    }

    public Dictionary<string, object> MakeDatabaseCall(Dictionary<string, object> testParams)
    {
        throw new NotImplementedException();
    }

    public bool CompareData(Dictionary<string, object> databaseValues,     Dictionary<string, object> responseValues)
        {
            throw new NotImplementedException();
        }
    }
}


<?xml version="1.0" encoding="utf-8" ?>
<TestParameterFile>
<Messages action="GETSystemDefined-Succesful"
        method="GET" expectedReponseCode ="200"/>

<Messages action="AddPatronMessage-InvalidPatronID"             
         method = "POST" expResponseCode="404" requestBody="{&quot;MessageType&quot;:     101,&quot;MessageValue&quot;: &quot;This is a free text message for this patron!&quot;}"/>

</TestParameterFile> 

这是我尝试实现的原始方式(我认为更好的方式),并且如果可能的话希望合并一个接口

using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Data.SqlClient;

namespace LEAPIntegrationTestingFINAL
{
    public abstract class TestCase
    {
        public static string authorizationString
        {
            get
            {
                string statusCode;
                AppConfig.Change("D:\\SampleProjects\\LEAP\\LEAPIntegrationTestingFINAL\\LEAPIntegrationTestingFINAL\\TestingSuiteConfiguration.config");

                //Converting User credentials to base 64.
                string uri = ConfigurationManager.AppSettings["authURL"];
                string uname = ConfigurationManager.AppSettings["username"];
                string pword = ConfigurationManager.AppSettings["password"];
                string _auth = string.Format("{0}:{1}", uname, pword);
                string _enc = Convert.ToBase64String(Encoding.ASCII.GetBytes(_auth));
                string _cred = string.Format("{0} {1}", "Basic", _enc);

                WebRequest authRequest = WebRequest.Create(uri);
                authRequest.Headers.Add(HttpRequestHeader.Authorization, _cred);
                authRequest.ContentLength = 0;
                authRequest.Method = "POST";


                //Creating and receiving WebResponse

                HttpWebResponse authResponse = (HttpWebResponse)authRequest.GetResponse();
                statusCode = Convert.ToString((int)authResponse.StatusCode);
                using (Stream responseStream = authResponse.GetResponseStream())
                {
                    using (StreamReader sr = new StreamReader(responseStream))
                    {
                        Dictionary<string, object> authResponseObject = new Dictionary<string, object>();
                        string authJSON = sr.ReadLine();
                        sr.Close();
                        responseStream.Close();

                        //Deserialization of jSON object and creating authorization String
                        JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
                        authResponseObject = jsSerializer.Deserialize<Dictionary<string, object>>(authJSON);
                        string AccessToken = authResponseObject["AccessToken"].ToString();
                        string AccessSecret = authResponseObject["AccessSecret"].ToString();
                        string authorizationString = "Authorization: PAS " + AccessToken + ":" + AccessSecret;
                        return authorizationString;
                    }
                }
            }
        }
        public string url { get; set; }
        public Dictionary<string, object> testParams { get; set; }
        public Dictionary<string, object> responseValues { get; set; }
        public Dictionary<string, object> databaseValues { get; set; }
        public bool comparisonValue { get; set; }




        public bool RunTest(string apiObject, string objectAction) 
        {
            bool comparisonValue = false;
            this.testParams = GetTestParams(apiObject, objectAction);
            this.url = RootURLBuilder.Build();
            this.url = ConfigureURL(this.url);
            #region ConfigRequestBody
            if (this.testParams.ContainsKey("requestBody"))
            {
                this.testParams = ConfigureRequestBody(this.testParams);
            }
            #endregion
            this.responseValues = ExecuteRequest(this.testParams);
            this.responseValues = ParseResponse(this.responseValues);
            #region MakeDatabaseCall
            if (this.testParams.ContainsKey("query"))
            {
                this.databaseValues = MakeDatabaseCall(this.testParams);
            }
            #endregion
            this.comparisonValue = CompareData(this.databaseValues, this.responseValues);
            return comparisonValue;
        }
        private Dictionary<string, object> GetTestParams(string apiObject, string objectAction) 
        {
            Dictionary<string, object> testParams = new Dictionary<string, object>();
            return testParams;
        }
        public abstract string ConfigureURL(string objectAction);
        public abstract Dictionary<string, object> ConfigureRequestBody(Dictionary<string,object> testParams);
        public Dictionary<string, object> ExecuteRequest(Dictionary<string, object> testParams) 
        {
            Dictionary<string, object> responseValues = new Dictionary<string, object>();
            string requestBody = null;
            string httpVerb = this.testParams["method"].ToString();
            #region requestBody = this.testParams["requestBody"].ToString();
            if (this.testParams.ContainsKey("requestBody"))
            {
                requestBody = this.testParams["requestBody"].ToString();
            }
            #endregion
            WebRequest req = WebRequest.Create(this.url);
            req.Headers.Add(authorizationString);
            req.ContentType = "application/json";
            req.Method = httpVerb;

            if (requestBody != null)
            {
                req.ContentLength = requestBody.Length;
                using (Stream reqStream = req.GetRequestStream())
                {
                    byte[] reqBodyBytes = Encoding.UTF8.GetBytes(requestBody);
                    reqStream.Write(reqBodyBytes, 0, reqBodyBytes.Length);
                }
            }
            else
                req.ContentLength = 0;
            using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
            {
                string responseJSON;
                int statusCode = (int)resp.StatusCode;
                string statusMessage = resp.StatusDescription;

                Stream respStream = resp.GetResponseStream();
                StreamReader sr = new StreamReader(respStream);
                responseJSON = sr.ReadToEnd();
                respStream.Close();
                sr.Close();

                responseValues.Add("statusCode", statusCode);
                responseValues.Add("statusMessage", statusMessage);
                responseValues.Add("responseJSON", responseJSON);
            }
            return responseValues;

        }
        public virtual Dictionary<string, object> ParseResponse(Dictionary<string, object> responseValues)
        {

            Dictionary<string, object> parsedResponseJSON = new Dictionary<string, object>();
            Dictionary<string, object> parsedResponse = new Dictionary<string, object>();
            string json = this.responseValues["responseJSON"].ToString();




            parsedResponse.Add("statusCode", this.responseValues["statusCode"]);
            parsedResponse.Add("statusMessage", this.responseValues["statusMessage"]);






            return parsedResponse;
        }
        public abstract Dictionary<string, object> MakeDatabaseCall(Dictionary<string, object> testParams);
        public abstract bool CompareData(Dictionary<string, object> databaseValues, Dictionary<string, object> responseValues);
    }

    public class PatronMessageTestCase : TestCase 
    {

        public override string ConfigureURL(string objectAction)
        {
            string url;

            switch (objectAction)
            {
                case "GETSystemDefined-Succesful":
                    url = this.url + "/patronmessages";
                    return url;
                default:
                    return "Not Found";
            }
        }

        public override Dictionary<string, object> ConfigureRequestBody(Dictionary<string, object> testParams)
        {
            throw new NotImplementedException();
        }

        public override Dictionary<string, object> MakeDatabaseCall(Dictionary<string, object> testParams)
        {
            throw new NotImplementedException();
        }

        public override bool CompareData(Dictionary<string, object> databaseValues, Dictionary<string, object> responseValues)
        {
            throw new NotImplementedException();
        }
    }

}

最后.....运行测试并使用 MSTest 控制的文件

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace LEAPIntegrationTestingFINAL
{
    [TestClass]
    public class LEAPTestingSuite
    {        
        [TestMethod]
        public void MessagesTests()
        {
            PatronMessageTestCase MessagesTests = new PatronMessageTestCase();
            Assert.AreEqual(true, MessagesTests.RunTest("Messages", "GETSystemDefined-Succesful"));
        }



        [TestMethod]
        public void AssociationsTests() 
        {

            PatronAssociationsTestCase GETSystemDefined = new PatronAssociationsTestCase();
            Assert.AreEqual(true, TestRunner.RunTest());
        }
    }
}

如果您需要其中的任何一个,我们还有更多的类让我知道......并且只是回顾一下,我的主要目标是进行 api 调用并确保返回的响应代码与 xml 文件中的 expectedResponseCode 匹配。我还可以选择进行数据库调用并确认某些数据库值与从 api 调用返回的某些数据相匹配。另外,我的同事建议使用界面

4

0 回答 0