2

我是第一次练习编写单元测试,我有一些问题。我将首先解释我要测试的内容。

我想测试一个看起来像这样的方法:

public bool IsAdmin(HubCallerContext hubCallerContext)
{
    return hubCallerContext.User.IsInRole("admin");
}

该方法在UserService连接到接口的类中实现IUserService

我正在尝试创建 2 个测试:

  • 一个具有 HubCallerContext 的角色,它扮演“管理员”的角色并将断言为真。
  • 一个具有 HubCallerContext 的“用户”角色并将断言为假。

我在我的解决方案中创建了一个新的类库,我在其中引用了我正在测试的项目。我已经安装了 NUnit 和 Moq,并创建了一个如下所示的测试类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChatProj;
using NUnit.Framework;
using ChatProj.Controllers;
using Moq;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using ChatProj.DAL;
using ChatProj.Service_Layer;
using System.Threading.Tasks;

namespace ChatProj.Tests
{
    [TestFixture]
    public class Class1
    {

        [SetUp]
        public void Setup()
        {

        }

        [Test]
    public void IsAdmin_CalledByAdmin_ReturnTrue()
    {
        UserService userService = new UserService();
        bool result = userService.IsAdmin( ? );
        Assert.IsTrue( result, "Something is wrong." );
    }

    [Test]
    public void IsAdmin_CalledByUser_ReturnFalse()
    {
        UserService userService = new UserService();
        bool result = userService.IsAdmin( ? );
        Assert.IsFalse( result, "Something is wrong." );
    }

    }
}

在这里,我开始感到困惑。(我用“?”标记了 IsAdmin 调用的参数,因为我不知道该放什么。)

我读过关于模拟、存根、假货和假人的文章,但这些定义是抽象的,以便我真正掌握。例如,我找到了这些定义:

 - Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.

 - Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).

 - Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.

 - Mocks are objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

当我设计了我的测试类时,我需要对我的 HubCallerContext 进行某种替换。这是假设我正在以正确的方式测试“IsAdmin”方法。

所以我的问题是:

  • 我是否以一种好的方式测试“IsAdmin”方法?

  • 我将如何实际进行测试?我是否使用模拟,在这种情况下,您能否展示我将如何实现它,或者指出我正确的方向? 以下是 HubCallerContext 的工作原理。

4

3 回答 3

4

假设HubCallerContext是这个 - https://github.com/SignalR/SignalR/blob/master/src/Microsoft.AspNet.SignalR.Core/Hubs/HubCallerContext.cs - 那么设置测试将很容易。您只IPrincipal需要.IsInRole("admin")两个IRequest.

语法会因使用的模拟框架而异,但您的测试最终会是这样的:

[Test]
public void IsAdmin_CalledByAdmin_ReturnTrue()
{
    UserService userService = new UserService();
    var principalMock = new Mock<IPrincipal>();
    principalMock.Setup(x => x.IsInRole("admin")).Returns(true);
    var requestMock = new Mock<IRequest>();
    requestMock.Setup(x => x.User).Returns(principalMock.Object);
    var result = userService.IsAdmin(new HubCallerContext(requestMock.Object, ""));
    Assert.IsTrue( result, "Something is wrong." );
}

[Test]
public void IsAdmin_CalledByUser_ReturnFalse()
{
    UserService userService = new UserService();
    var principalMock = new Mock<IPrincipal>();
    principalMock.Setup(x => x.IsInRole("admin")).Returns(false);
    var requestMock = new Mock<IRequest>();
    requestMock.Setup(x => x.User).Returns(principalMock.Object);
    var result = userService.IsAdmin(new HubCallerContext(requestMock.Object, ""));
    Assert.IsFalse( result, "Something is wrong." );
}

我没有检查上述是否编译,但它基于Moq所需的语法。

于 2013-11-11T14:46:51.640 回答
3

我认为如果您稍微更改被测方法(假设它不是遗留代码的一部分),您编写这两个单元测试会容易得多。

如果您以这种方式定义方法:

public bool IsAdmin(IPrincipal user)
{
    return user.IsInRole("admin");
}

事情会变得非常简单(顺便说一句。检查“得墨忒耳法则”;))。您可以传入一个模拟对象(因为用户参数是一个接口 - IPrincipal),如果用户应该是角色“admin”,则返回 true,否则返回 false。

此解决方案的好处是您不必构建模拟对象图,并且测试的排列部分非常简单。您的测试可能看起来像这样:

    [Test]
    public void IsAdmin_CalledByAdminUser_ReturnTrue()
    {
        //Arrange
        var principalMock = new Mock<IPrincipal>();
        principalMock.Setup(x => x.IsInRole("admin")).Returns(true);

        //Act
        var userService = ...// create an instance of userService here
        var result = userService.IsAdmin(principalMock);

        //Assert
        Assert.IsTrue(result);
    }

    [Test]
    public void IsAdmin_CalledByNonAdminUser_ReturnFalse()
    {
        //Arrange
        var principalMock = new Mock<IPrincipal>();
        principalMock.Setup(x => x.IsInRole("admin")).Returns(false);

        //Act
        var userService = ...// create an instance of userService here
        var result = userService.IsAdmin(principalMock);

        //Assert
        Assert.IsFalse(result);
    }

我建议您阅读这一系列博客文章(我认为这很酷:)):http ://www.daedtech.com/tag/unit-testing

于 2013-11-11T15:59:18.210 回答
-2

您可以使用 获取角色列表并检查每个角色foreach

于 2013-11-11T14:27:39.120 回答