【问题标题】:Integration tests - what would you test for in this controller?集成测试——你会在这个控制器中测试什么?
【发布时间】:2018-10-26 19:01:00
【问题描述】:

我在 .NET Web API 2 项目中的控制器端点上应用 NUnit 集成测试,该项目的模型和控制器是通过 Entity code first from database 生成的。

我不知道应该测试控制器的哪些部分。 最后,我们只是希望能够自动化“具有“x”角色的用户可以获取这些数据吗?”

查看此控制器的GET 部分,您将测试哪些部分以及您的推理是什么?

namespace api.Controllers.myNamespace
{

    public class myController : ApiController
    {
        private string strUserName;
        private string strError = "";
        private string strApiName = "myTable";
        private myDatabase db = new myDatabase();

        // ----------------------------------------------------------------------

        // GET: api/path
        public IQueryable<myTable> GetmyTable()
        {
            try
            {
                this.strUserName = this.getUserName();

                if
                (
                    // ----- authorize -----
                    db.view_jnc_role_api_permission.Count
                    (
                        view =>
                        (
                            view.permission == "get"
                            && view.apiName == this.strApiName
                            && view.userName == this.strUserName
                        )
                    ) == 1
                // ----- /authorize -----
                )
                {
                    // ----- get -----
                    IQueryable<myTable> data =

                    from tbl in db.myTable

                    where tbl.deleted == null

                    select tbl;
                    // ----- /get -----

                    return data;
                }
                else
                {
                    strError = "Unauthorized.";
                    throw new HttpResponseException(HttpStatusCode.Forbidden);
                }
            }
            catch (Exception ex)
            {
                if (strError.Length == 0)
                {
                    if (this.showException())
                    {
                        strError = ex.ToString();
                    }
                }

                throw new HttpResponseException(ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, strError));
            }
        }

}


作为参考,这是我到目前为止所拥有的。我正在定义的这些私有字段中的一些不应该在这里 - 目前正试图通过 AssemblyInfo.cs 从我的测试项目中访问私有方法来解决这个问题:

namespace api.myNamespace
{
        [TestFixture]
        public class myController : ApiController
        {
            private string strUserName;
            private string strError = "";
            private string strApiName = "myTable";
            private myDb db = new myDb();
            // Using TransactionScope to (hopefully) prevent integration test's changes to database from persisting
            protected TransactionScope TransactionScope;
            // Instantiate _controller field
            private myController _controller;

            [SetUp]
            public void SetUp() {
                TransactionScope = new TransactionScope(TransactionScopeOption.RequiresNew);
                // It's possible that one test may leave some state which could impact subsequent tests - so we must reinstantiate _controller at the start of each new test:
                _controller = new myController();
            }

            [TearDown]
            public void TearDown()
            {
                TransactionScope.Dispose();
            }



            **//------ TESTS -------//
            // CanSetAndGetUserName
            // AuthorizedUserCanGetData
            // UnauthorizedUserCannotGetData
            // AuthorizedUserCanPutData
            // UnauthorizedUserCannotPutData
            // AuthorizedUserCanPostData
            // UnauthorizedUserCannotPostData
            // AuthorizedUserCanDeleteData
            // UnauthorizedUserCannotDeleteData**

            [Test]
            public void CanGetAndSetUsername()
            {
            // ARRANGE
            var user = _controller.getUserName();

            // ACT

            // ASSERT
            Assert.That(user, Is.EqualTo("my-internal-username"));
            }

        [Test]
        public void UnauthorizedUserCannotGetData()
        {
            var user = "Mr Unauthorized";
            // Unfinished bc integration testing is super abstract, subjective, hard, time consuming and hard. All downvoters are plebs.
            Assert.That(user, Is.EqualTo());

        }
            }
    }

}

【问题讨论】:

标签: c# .net unit-testing nunit integration-testing


【解决方案1】:

集成测试意味着几件事:

  1. 您在数据库中设置测试数据,例如通过脚本。
  2. 您调用被测端点时确切知道应该使用什么数据调用它以及应该得到什么。这一切都基于您在第 1 步中设置的测试数据。
  3. 您将预期数据与返回的数据进行比较。

这是一个集成测试,因为它涉及所有内容,包括 api 和数据库。

现在,您说您在决定要测试控制器的哪些部分时遇到了麻烦。这表明您将集成测试与单元测试混淆了。

我们已经介绍过的集成测试。 单元测试涵盖部分功能。你不测试控制器,算了。

你真正需要考虑的是:

首先,将您的代码与控制器分开。保持控制器非常基本。它接收调用,验证请求模型并将其进一步传递给发生功能的类库。这使您可以忘记“测试控制器”并专注于您的功能。单元测试在这里会有所帮助,您的测试用例将变成这样

  1. 我有一个用户,以某种方式设置。
  2. 我有一些数据,以某种方式设置
  3. 当我调用方法 X 时,我应该得到这个响应。

有了这样的设置,您可以按照自己喜欢的方式设置测试数据并检查每个测试用例。

您想知道如何测试控制器的唯一原因是因为您将所有代码都转储到其中,这当然会使一切变得困难。思考 SOLID,思考 SOC(关注点分离)。

一条建议:永远不要从端点返回 IQueryable,这不是数据,只是一个尚未运行的查询。返回一个列表,IEnumerable,一个单数对象,无论你需要什么,只要确保你首先通过调用 ToList() 来执行它,例如首先在你的 IQueryable 表达式上。

所以,步骤是这样的:

  1. 首先设置您的 IQueryable
  2. 通过调用 ToList()、First()、FirstOrDefault() 来执行它并返回结果。

【讨论】:

  • 感谢您的回复!我有很多考虑要做……我们有少量的开发人员来完成这个项目。集成测试可能会为这个项目增加很多我们没有的时间(尤其是考虑到我们之前没有人做过,而且网络上的集成测试文档很少)。即便如此 - 我们的测试可能仍然是“不诚实的”并且写得不好,并且随着我们知识的成熟必须反复更改。对于我们的具体情况,可能不可行:(。仅供参考,我们的控制器是由实体自动生成的。无论如何,我都会进一步研究您的 IQueryable 建议
  • 您可以从简单的开始,因为单元测试开始测试以某种受控方式更改数据的功能。你不必做太多。编写测试教你一件非常重要的事情:如何编写可测试的代码,这才是真正的主要内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多