我有一个必须编写单元测试的代码。 由于我是单元测试的新手,因此我正在寻求您的帮助。 我想测试IsAdmin方法,该方法将输入CloudTableClient和一个字符串作为输入,但是我真的不知道如何处理它。 我尝试了下面的代码,但失败,并显示以下消息:
消息:测试方法UnitTestMatan.UserControllerTests.IsAdmin_NotOnTheList_ReturnFalse抛出异常: System.MethodAccessException:尝试通过方法'MatanWebServer.Controllers.UserController.IsAdmin(Microsoft.WindowsAzure.Storage.Table.CloudTableClient,System.String)'访问方法'Microsoft.WindowsAzure.Storage.Table.CloudTable.ExecuteQuery(Microsoft.WindowsAzure .Storage.Table.TableQuery,Microsoft.WindowsAzure.Storage.Table.TableRequestOptions,Microsoft.WindowsAzure.Storage.OperationContext)'。
基本上,我要测试的第一件事是IsAdmin在收到不在表中或只是随机字符串的电子邮件时将返回false。 在测试部分,我想使用UserController中生成的表,而不要构建一个新表。
以下是我需要测试的课程:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using ParseMatanDataWebJob;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace MatanWebServer.Controllers
{
public class UserController : ApiController
{
// GET: api/user
[AdminAuthorizeAttribute]
public IEnumerable<string> Get()
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=http;AccountName=matandata;AccountKey=myconnectionstringthatidontwantyoutoknow");
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
IEnumerable<string> EmailsList = GetAllEmails(tableClient);
return (EmailsList);
}
// GET: api/user/5
[UserAuthorizeAttribute]
public ReturnObjectValuescontroller Get(string email)
{
// Retrieve the storage account from the connection string.p
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("myconnectionstringthatidontwantyoutoknow");
// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
var result = new ReturnObjectValuescontroller();
result.isAdmin = IsAdmin(tableClient, email);
// Create the CloudTable object that represents the "people" table.
CloudTable donationsTable = tableClient.GetTableReference("userdonationsdata");
// Create the table query.
TableQuery<DonationData> userDonationsQuery = new TableQuery<DonationData>().Where(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, email.ToString()));
var DonationsResult = donationsTable.ExecuteQuery(userDonationsQuery).ToList();
result.DonationsList = DonationsResult;
return result;
}
public static bool IsAdmin(CloudTableClient tableClient, string email)
{
CloudTable AdminsTable = tableClient.GetTableReference("matanadminusers");
TableQuery AdminsListQuery = new TableQuery();
AdminsListQuery.SelectColumns = new List<string>() { "AdminEmail" };
var TableEntityAdminsList = AdminsTable.ExecuteQuery(AdminsListQuery).ToList();
List<string> AdminsEmailList = new List<string>();
foreach (var item in TableEntityAdminsList)
{
AdminsEmailList.Add(item.Properties["AdminEmail"].StringValue);
}
return (AdminsEmailList.Contains(email, StringComparer.OrdinalIgnoreCase));
}
private IEnumerable<string> GetAllEmails(CloudTableClient tableClient)
{
CloudTable donationsTable = tableClient.GetTableReference("useremails");
TableQuery EmailsListQuery = new TableQuery();
EmailsListQuery.SelectColumns = new List<string>() { "RowKey" };
var DynamicEntityEmailsList = donationsTable.ExecuteQuery(EmailsListQuery).ToList();
List<string> EmailList = new List<string>();
foreach (var item in DynamicEntityEmailsList)
{
EmailList.Add(item.RowKey);
}
return EmailList.Distinct();
}
// POST: api/Rony
public void Post([FromBody]string value)
{
}
// PUT: api/Rony/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE: api/Rony/5
public void Delete(int id)
{
}
}
}
这是我为IsAdmin尝试的测试:
using System;
using MatanWebServer.Controllers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
namespace UnitTestMatan
{
[TestClass]
public class UserControllerTests
{
[TestMethod]
public void IsAdmin_NotOnTheList_ReturnFalse()
{
var userController = new UserController();
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("myconnectionstringthatidontwantyoutoknow");
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
var result = UserController.IsAdmin(tableClient, "str");
Assert.IsFalse(result);
}
}
}
答案 0 :(得分:1)
这是对“ increddibelly”给出的关于使用接口的答案的进一步跟进。
让我们举一个例子:
我有一个名为Person的类,该类需要将一些信息发送到数据库。然后,我将在另一个类中使用它,而不是在Person类中使用该逻辑。此类负责包含Person类与数据库进行通信所需的所有逻辑,此类通常称为数据访问层(DAL)或存储库。好的,举个例子:
Person类:
public Person(IDALPerson d)
{
dal = d;
}
private IDALPerson dal;
public void SendOrder()
{
(Other logic...)
dal.SendOrder("Bananas");
}
因此,这里的Person类通过其构造函数从程序的另一个位置获取此DAL(依赖关系),这是一种依赖关系注入。该DAL实现了IDALPerson接口,因此具体的DAL类可以是:
public class PersonDAL : IDALPerson
{
public void SendOrder()
{
(logic for adding order)
}
}
然后在执行测试时,您可以创建一个IDALPerson的模拟对象,并以此方式在测试时,您的Person类实际上不使用数据库,然后您可以通过使用Moq框架来获取一些信息,如“ increddibelly”所述。 ”,从而在不依赖数据库的情况下测试SendOrder函数。 您的测试可能如下所示:
[Test]
public void SendOrderTest()
{
//Arrange
Mock<IDALPerson> MockDAL = new Mock<IDALPerson>();
Person p = new Person(MockDAL);
//Act
p.SendOrder();
//Assert
//Assert something.
}
答案 1 :(得分:0)
对于任何和所有单元测试(队列雪花边缘情况),您都想用虚拟/模拟/伪造对象替换代码所依赖的组件。 Moq有一个很棒的库供我们使用。
说您的代码需要一个
IStuffCreator
具有
Stuff CreateStuff()
方法,您可以按以下方式控制此外部组件的结果:
var sc = Mock<IStuffCreator>();
sc.Setup(x => x.CreateStuff()).Returns(new Stuff { Id = 1} );
MyClass classUnderTest = new classUnderTest(sc.Object);
任何对ClassUnderTest的调用都涉及CreateStuff方法的调用,都会得到一个ID为1的新Stuff,因为您是通过这种方式设置了假组件的。
如果您需要使用Azure告诉您的代码中有一个管理员,则可以执行相同的操作。
var iauth = new Mock<IAzureAuthenticator>()
iauth.Setup(x => x.IsAdmin(It.IsAny<TableClient>, It.IsAny<string>())).Returns(true);
或者如果您只想设置特定的案例:
var myTableClient = new TableClient { Id = 123 };
iauth.Setup(x => x.IsAdmin(myTableClient, It.IsAny<string>)).Returns(true);
但是随后您可能希望将所有其他情况设置为返回false,以便您完全确定测试值会更改行为。
iauth.Setup(x => x.IsAdmin(It.IsAny<TableClient>(), It.IsAny<string>)).Returns(false);
iauth.Setup(x => x.IsAdmin(myTableClient, It.IsAny<string>)).Returns(true);
希望事情就这么简单-但我确定你明白了。
如果这对您不起作用,通常意味着您不依赖接口,而是依赖显式实现。由于依靠接口而不是实现是一种可靠的改进(heh),因此您现在有很大的机会来改进代码;)