Question

So, I have my own implementation of Luhn's algorithm and I'm using a Regular Expression to validate the User's input.

I proceed to do the unit testing, and I'm finding myself in this problem:

Mock<Regex> regexMock = new Mock<Regex>();
regexMock.Setup(r => r.IsMatch(It.IsAny<string>())).Returns(true);

Note: I'm using Moq framework to do the mocking

But somehow, the last line of code is throwing an Exception

Invalid setup on a non-virtual (overridable in VB) member: r => r.IsMatch(It.IsAny<string>())

I would like to know what alternatives do I have to solve my problem of mocking, or maybe some workaround that can be made.

Thanks in advance!

Edit:

Ok, so my Test looks like this:

Mock<Regex> regexMock = new Mock<Regex>();
regexMock.Setup(r => r.IsMatch(It.IsAny<string>())).Returns(true);

Mock<IRegexBuilder> builderMock = new Mock<IRegexBuilder>();
builderMock.Setup(m => m.Build()).Returns(regexMock.Object);

LuhnAlgorithm luhn = new LuhnAlgorithm(builderMock.Object);

string input = "7992739871";
ushort expected = 3;

object output = luhn.GenerateChecksum(input);

Assert.IsInstanceOfType(output, typeof(ushort));
Assert.AreEqual(expected, (ushort)output);

I have this IRegexBuilder which is another class I made to help the creation of Regex. What it is important is that the final Regex object is made with a call to the IRegexBuilder.Build() method.

Now, I can mock that method and return a fixed Regex, like:

builderMock.Setup(m => m.Build()).Returns(new Regex("\d+"));

but I don't want to define my validation on the Test.

Guys, I want my validation (however it is made) to not influence my testing, I would like to mock the input matching to return true or false, independently of how the validation is made. If I create my own Regex in the Test Method, then whenever I change my validation logic in the future, I would have to change the Test.

Was it helpful?

Solution

Why mock a regex?

While regex is an internal dependency of your Luhn implementation, it's not a dependency that should be injected, and therefore should not be mocked.

If doing a Luhn check is a dependency on your validation code, and what to validate that it does do a Luhn check, you could have an interface / abstract class, where an implementation could do regex internally.

A possibility could be

interface ICardValidator
{
    bool IsCardValid(string cardNumber);
}

class LuhnCardValidator : ICardValidator
{
    private static readonly Regex _cardRegex = new Regex(...);

    bool IsCardValid(string cardNumber)
    {
        return Regex.IsMatch(cardNumber);
    }
}

You can write unit tests against LuhnCardValidator to verify that your Luhn check works.

[Test]
[TestCase("4242424242424242")
public void ShouldBeValid(string cardNumber)
{
    Assert.IsTrue(new LuhnCardValidator().IsCardValid(cardNumber));
}

You can also write tests against your code that depends on ICardValidator to say for example when validation fails it presents the user the appropriate error message.

[Test]
public void ShouldPresentCardFailedMessage()
{
    var mockCardValidator = new Mock<ICardValidator>();
    mockCardValidator.Setup(x => x.IsCardValid(It.IsAny<string>()).Returns(false);

    var validationSummary = new ValidationSummary(mockCardValidator.Object);

    validationSummary.ValidateThePage(...);

    var errors = validationSummary.GetErrors();

    Assert.IsTrue(errors.Any(x => x.Message == "Credit card number is not valid"));
}

OTHER TIPS

If the regular expression represents a complex algorithm, you could encapsulate the matching in a custom class with an interface and dependency-inject that (or a mock of that).

If it's basic validation, I wouldn't mock it at all. Would you mock String.Contains()?

When you are creating mock with Moq, it creates class which implements interface you are mocking, or class inherited from class which you are mocking. This generated class should provide its own implementation of member you are mocking. With interface its simple, because there is no implementation. With class member should be abstract or virtual. Regex.IsMatch is not abstract, nor virtual. So Moq just can't create its own implementation of this member in order to make setup.

You should use something which Moq can handle. Usually some wrapper class which has virtual methods or implements some interface. This class should delegate work to Regex class:

public interface IWrapper // use appropriate name of interface
{
    bool IsValid(string value)
}

This interface can be easily mocked. You can now write tests for clients which use this interface. For real life you will need implementation which delegates work to Regex:

public class Wrapper : IWrapper
{
   public bool IsValid(string value)
   {
       // use Regex here
   }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top