关于c#:集成测试-您将在此控制器中测试什么?

Integration tests - what would you test for in this controller?

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

我在考虑应该测试控制器的哪些部分时遇到了麻烦。 最后,我们希望能够自动化"具有" x"角色的用户能否获取此数据?"

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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从我的测试项目中访问私有方法来解决此问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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());

        }
            }
    }

}

集成测试意味着几件事:

  • 您可以通过例如脚本在数据库中设置测试数据。
  • 您可以调用被测端点,确切知道应该使用什么数据以及应该获得什么数据。这全部基于您在步骤1中设置的测试数据。
  • 您可以将预期数据与返回的数据进行比较。
  • 这是一个集成测试,因为它涉及到api和数据库的所有内容。

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

    我们已经介绍过的集成测试。
    单元测试涵盖部分功能。您无需测试控制器,就不用管它了。

    您真正需要考虑的是:

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

  • 我有一个用户,以某种方式设置。
  • 我有一些数据,以某种方式设置
  • 当我调用方法X时,我应该得到这个响应。
  • 有了这样的设置,您可以按自己喜欢的方式设置测试数据并检查每个测试用例。

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

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

    因此,步骤如下:

  • 首先设置您的IQueryable
  • 通过调用ToList(),First(),FirstOrDefault()来执行它,然后返回结果。