How to Unit Test this method?

I have a problem with unit Test this method. It seems clear to me at first, but then I have a hard time understanding how to effectively inject / mock my array in 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);
        }
   ...

}

      

I want to test the notExist method. I started below and then wondered how to mock the meaning of my context for a class? Is there a way to present or mock the context? I'm using moq to mock my dummy data, but I just don't see it here. Also, it is not a controller class.

 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/"));

        }

      

}

Refresh

When I changed my test to

 [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/"));

        }

      

and changed my validation class to

public IUrlShortenersRepository context;
public UrlValidation(IUrlShortenersRepository repo)
{
  context = repo;
...

      

My test run has no problem, however, it fails. But I was unable to start the project again. Bcos. My free validation class requires a parameter, which I'm not sure where to go. I have set the validation class in the model as shown below

 [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; }

    }

      

I'm not sure where to enter the parameter.

In the meantime, when I check the link below I get a clear example and so changed my test to

 [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/"));

        }

      

I am getting an invalid installation error 'system.notsupportedexception on non-virtual error thrown in fakeContext.Setup(ctx => ctx.Urls).Returns(mockSet.Object);

. I suspect my EFDContext cannot be overrated as the user explains below. I'm not sure how to fix this. My EFDContext class is declared in context as shown below.

namespace UrlShortener.Domain.Concrete
{
    public class EFDbContext:DbContext
    {
        public DbSet<Url> Urls { get; set; }
    }
}

      

Then I changed the EFDContext properties to virtual here

namespace UrlShortener.Domain.Concrete
{
    public class EFDbContext:DbContext
    {
        public virtual DbSet<Url> Urls { get; set; }
    }
}

      

My test is now running system.TargetInvocationException With an inner exception "Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type."}

. Message The type initializer for 'Castle.Proxies.DbSet

1Proxy 'throws an exception. The error has been dropped in

fakeContext.Setup(ctx => ctx.Urls).Returns(mockSet.Object);

+3


source to share


1 answer


Typically, you inject dbcontext or any other costly / complex test dependency into the class under test using some form of dependency injection (as a public network device constructor argument, using a service locator ...).

This way, you can inject a fake unit test implementation that gets clogged with fake data and / or fake expectations when calling methods.



You can wrap a thin header interface around your EFDbContext class to allow unit testing, or you can just make some properties in the real EFDbContext virtual as described 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/"));

        }

      

0


source







All Articles