1

I'm trying to test validation that I've setup for my wcf service. What's the best way to do it?

[ServiceContract]
[ValidationBehavior]
public interface IXmlSchemaService
{

    [OperationContract(Action = "SubmitSchema")]
    [return: MessageParameter(Name = "SubmitSchemaReturn")]
    [FaultContract(typeof(ValidationFault))]
    JobData SubmitSchema([XmlStringValidator] string xmlString);
}

XmlStringValidator is a custom validator I've created. Ideally I want something like:

XmlSchemaService service = new XmlSchemaService();
service.SubmitSchema();

But in this case, validation isn't called.

Steven
  • 166,672
  • 24
  • 332
  • 435
Bogdan Kanivets
  • 552
  • 2
  • 9
  • 17

2 Answers2

2

By definition, this sort of test is an integration test, not a unit test. The VAB validation will only take place if the service operation is invoked via the WCF pipeline.

While you could perhaps force your calls through the WCF pipeline without creating a client proxy, wouldn't it make more sense to test this from a client proxy in order to ensure that the client is seeing exactly the fault you wish to publish from your service when the validation fails?

Nicole Calinoiu
  • 20,843
  • 2
  • 44
  • 49
1

You can test out the validation in isolation. While it is not feasible to have validation invoked when running the service code directly, the Validation Application Block has two methods for testing your code (that I am aware of).

  1. Using the ValidatorFactory to create a validator for your input type and Assert that the validation results contain the expected errors.
  2. Instantiating the Validator directly and testing it with various input.

In practice I end up using a combination of the two techniques. I use method one to test for validation errors on complex input types. As an example:

[DataContract]
public class Product
{
    [DataMember, NotNullValidator]
    public string Name { get; set; }

    [DataMember, RangeValidator(0.0, RangeBoundaryType.Exclusive, 
        double.MaxValue, RangeBoundaryType.Ignore,
        ErrorMessage = "The value cannot be less than 0.")]
    public double Price { get; set; }    
}

[TestMethod]
public void InvalidProduct_ReturnsValidationErrors()
{
    Product request = new Product()
    {
        Price = -10.0
    };
    var validatorFactory = EnterpriseLibraryContainer.Current
        .GetInstance<ValidatorFactory>();
    var validator = validatorFactory.CreateValidator<Product>();
    var results = validator.Validate(request);

    Assert.IsTrue(results.Any(vr => vr.Key == "Name" 
        && vr.Message == "The value cannot be null."));
    Assert.IsTrue(results.Any(vr => vr.Key == "Price" 
        && vr.Message == "The value cannot be less than 0."));
}

For method 2 I would have tests that cover my use case scenarios for Validators I've created. As another example:

[TestMethod]
public void XmlStringValidator_ReturnsErrors_OnInvalidInput()
{
    var validator = new XmlStringValidator();

    var results = validator.Validate("Your input goes here");

    Assert.IsTrue(results.Any(vr => vr.Key == "[KeyNameInValidator]" && 
        vr.Message == "[Expected error message based on input]"));
}

Method 2 will allow you to create as many test scenarios as you would like for your XmlStringValidator.

You can find more information about these methods in this article: Chapter 6 - Banishing Validation Complication

Phil Patterson
  • 1,242
  • 15
  • 25