我第一次练习单元测试,我有一些问题。我将通过解释我试图测试的内容开始。
我想测试一个看起来像这样的方法:
public bool IsAdmin(HubCallerContext hubCallerContext)
{
return hubCallerContext.User.IsInRole("admin");
}
该方法在类UserService
中实现,该类连接到接口IUserService
。
我试图创建2个测试:
我已经在我的解决方案中创建了一个新的类库,在那里我已经参考了我正在测试的项目。我已经安装了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." );
}
}
}
在这里,我开始感到困惑。 (我用&#34标记了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"方法好吗?
我如何实际进行测试?我是否使用模拟器,在这种情况下,您能说明我将如何实现它,或指向正确的方向? Here is how the HubCallerContext works for refrence.
答案 0 :(得分:4)
假设HubCallerContext
就是这个 - https://github.com/SignalR/SignalR/blob/master/src/Microsoft.AspNet.SignalR.Core/Hubs/HubCallerContext.cs - 那么设置测试将很容易。你只需要两个IPrincipal
的模拟,其中一个为.IsInRole("admin")
调用返回true,另一个返回false.wrap这两个模拟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所需的语法。
答案 1 :(得分: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
答案 2 :(得分:-2)
您可以使用foreach
获取角色列表并检查每个角色。