我在尝试单元测试此方法时遇到问题。我首先看起来很清楚,但后来我很难理解如何有效地将我的数组注入/模拟到bdcontext
public class UrlValidation: AbstractValidator<UrlShortenerModel>
{
Uri uriResult;
private EFDbContext context;
.....
public bool notExist(string url)
{
//Check if The Url Exist . This is to stop replication of Urls.
bool exist = context.Urls.Any(x => x.OriginalUrl == url);
return (exist == false);
}
...
}
我想测试方法notExist。我从下面开始,然后坚持如何模拟我的上下文对类的价值?有没有办法表达或嘲笑上下文?我正在使用moq模拟我的虚拟数据,但我只是没有看到这里的方式。加上它不是控制器类。
public void Should_know_if_Url_Exist_or_Not()
{
ArrayList arr = new ArrayList();
arr.AddRange(new Url[]
{
new Url{ UrlId = 0, UrlCode = "TYUR", OriginalUrl="https://fluentvalidation.com", IpAddress="127.0.0.1", PostedDate = DateTime.Now},
new Url{ UrlId = 1, UrlCode = "TwUR", OriginalUrl="https://facebook.com", IpAddress="127.0.0.1", PostedDate = DateTime.Now},
new Url{ UrlId = 2, UrlCode = "TkUR", OriginalUrl="https://youtube.com/", IpAddress="127.0.0.1", PostedDate = DateTime.Now}
});
Assert.IsTrue(val.notExist("https://www.youtube.com/"));
Assert.IsFalse(val.notExist("https://www.facebook.com/"));
}
}
更新
当我将测试更改为
时 [TestMethod]
public void Should_know_if_Url_Exist_or_Not()
{
Mock<IUrlsRepository> mock = new Mock<IUrlsRepository>();
mock.Setup(u => u.Urls).Returns(new Url[] {
new Url{ UrlId = 0, UrlCode = "TYUR", OriginalUrl="https://fluentvalidation.com", IpAddress="127.0.0.1", PostedDate = DateTime.Now},
new Url{ UrlId = 1, UrlCode = "TwUR", OriginalUrl="https://facebook.com", IpAddress="127.0.0.1", PostedDate = DateTime.Now},
new Url{ UrlId = 2, UrlCode = "TkUR", OriginalUrl="https://youtube.com/", IpAddress="127.0.0.1", PostedDate = DateTime.Now}
}.AsQueryable());
var validator = new UrlValidation(mock.Object);
Assert.IsTrue(validator.notExist("https://www.youtuberre.com/"));
Assert.IsFalse(validator.notExist("https://www.facebook.com/"));
}
并将我的验证类修改为
public IUrlShortenersRepository context;
public UrlValidation(IUrlShortenersRepository repo)
{
context = repo;
...
我的测试运行没有问题,但它失败了。但我无法再次运行该项目bcos我的流利验证类需要一个参数,我不知道从哪里通过。我在下面的模型中设置我的验证类
[Validator(typeof(UrlValidation))]
public class UrlShortenerModel
{
//The Model for the Home form. The Url shortener form.
public string strUrl { get; set; }
public IEnumerable<Url> urlList { get; set; }
}
我不确定在哪里注入参数。
还有一秒,当我查看下面提供的链接时,我得到一个明确的例子,因此将我的测试修改为
[TestMethod]
public void Should_know_if_Url_Exist_or_Not()
{
var arr = new List<Url>
{
new Url{ UrlId = 0, UrlCode = "TYUR", OriginalUrl="https://fluentvalidation.com", IpAddress="127.0.0.1", PostedDate = DateTime.Now},
new Url{ UrlId = 1, UrlCode = "TwUR", OriginalUrl="https://facebook.com", IpAddress="127.0.0.1", PostedDate = DateTime.Now},
new Url{ UrlId = 2, UrlCode = "TkUR", OriginalUrl="https://youtube.com/", IpAddress="127.0.0.1", PostedDate = DateTime.Now}
}.AsQueryable();
var mockSet = new Mock<DbSet<Url>>();
mockSet.As<IQueryable<Url>>().Setup(m => m.Provider).Returns(arr.Provider);
mockSet.As<IQueryable<Url>>().Setup(m => m.Expression).Returns(arr.Expression);
mockSet.As<IQueryable<Url>>().Setup(m => m.ElementType).Returns(arr.ElementType);
mockSet.As<IQueryable<Url>>().Setup(m => m.GetEnumerator()).Returns(arr.GetEnumerator());
var fakeContext = new Mock<EFDbContext>();
fakeContext.Setup(ctx => ctx.Urls).Returns(mockSet.Object);
var validator = new UrlValidation();
validator.context = fakeContext.Object;
Assert.IsTrue(validator.notExist("https://www.youtube.com/"));
Assert.IsFalse(validator.notExist("https://www.facebook.com/"));
}
我在fakeContext.Setup(ctx => ctx.Urls).Returns(mockSet.Object);
抛出了'非虚拟'错误的'system.notsupportedexception无效设置'。我怀疑我的EFDContext不能被覆盖,如下面的用户所解释。我不知道如何解决这个问题。我的EFDContext类在上下文中声明如下。
namespace UrlShortener.Domain.Concrete
{
public class EFDbContext:DbContext
{
public DbSet<Url> Urls { get; set; }
}
}
然后我将EFDContext的属性更改为虚拟
namespace UrlShortener.Domain.Concrete
{
public class EFDbContext:DbContext
{
public virtual DbSet<Url> Urls { get; set; }
}
}
我的测试现在抛出system.TargetInvocationException
WITH内部异常"Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type."}
。消息The type initializer for 'Castle.Proxies.DbSet
1Proxy'抛出异常。错误被抛出
fakeContext.Setup(ctx => ctx.Urls).Returns(mockSet.Object);
答案 0 :(得分:0)
通常,通过使用某种形式的依赖注入(作为构造函数参数,使用公共setter,使用服务定位器,...),将dbcontext或任何其他昂贵/难以测试的依赖项注入到测试的类中
通过这种方式,您可以为单元测试注入虚假实现,这些实现存在伪造数据和/或对方法调用的虚假期望。
您可以在EFDbContext类周围包含一个精简header interface以允许进行单元测试,或者您可以在真实的EFDbContext虚拟上创建一些属性,如here所述。
public void Should_know_if_Url_Exist_or_Not()
{
ArrayList arr = new ArrayList();
arr.AddRange(new Url[]
{
new Url{ UrlId = 0, UrlCode = "TYUR", OriginalUrl="https://fluentvalidation.com", IpAddress="127.0.0.1", PostedDate = DateTime.Now},
new Url{ UrlId = 1, UrlCode = "TwUR", OriginalUrl="https://facebook.com", IpAddress="127.0.0.1", PostedDate = DateTime.Now},
new Url{ UrlId = 2, UrlCode = "TkUR", OriginalUrl="https://youtube.com/", IpAddress="127.0.0.1", PostedDate = DateTime.Now}
});
var fakeContext = new Mock<EFDbContext>();
fakeContext
.Setup(ctx => ctx.Urls)
.Returns(arr);
var validator = new UrlValidation(fakeContext.Object);
Assert.IsTrue(val.notExist("https://www.youtube.com/"));
Assert.IsFalse(val.notExist("https://www.facebook.com/"));
}