0

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.

4
  • 2
    Why are you trying to mock this? What are you trying to test? It would help if you could show the shape of your code and the test you're trying to write. Commented May 8, 2014 at 14:30
  • I agree with Jon... I can't think of a scenario where mocking a regex makes sense. Commented May 8, 2014 at 14:32
  • Another abuse of mocking. Are you testing the .NET framework itself?? You can easily pass two different pieces of data into your actually testable method and have one test required to pass, one to fail. Treat mocking like salt - none or too much and you've got bad tasting meal Commented May 8, 2014 at 14:37
  • Ok, I editted my question with more details Commented May 8, 2014 at 14:42

3 Answers 3

4

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"));
}
Sign up to request clarification or add additional context in comments.

2 Comments

I like the Validation Encapsulation alternative, but isn't there an easiest way without creating new interfaces and classes?
I decided to create an interface because that will act as your dependency and let you do dependency injection. It might be a little over-doing it to do a simple luhn check, but I find it's the easiest way to setup a unit test context.
3

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()?

2 Comments

Encapsulation of the matching could be an option. What I don't want is create the Regex in the test. See edited answer
I'd go with @Matthew's answer; he shows a good example. Don't be afraid to create new interfaces and classes - that's what OO programming is all about! :)
0

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.