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.
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?
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).
Using the ValidatorFactory to create a validator for your input type and Assert that the validation results contain the expected errors.
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
Related
I am very new to unit tests and recently started learning it from various online resources.
But still it confuses me when I need to implement it in my code.
For the given image which I have attached here, could anyone of you suggest me how should I start or where to start?
This is Azure function which I will be creating unit test for, framework/library I would prefer is Xunit and moq.
As mentioned in a comment, a good place to start when unit testing is looking at your code and identifying the different "paths" it can take and what the result of that path will be.
if (inventoryRequest != null)
{
// path 1
await _inventoryService.ProcessRequest(inventoryRequest);
_logger.LogInformation("HBSI Inventory Queue trigger function processed.");
}
else
{
// path 2
_logger.LogInformation("Unable to process HBSI Rate plan Queue.");
}
In your code, because of your if statement, there are 2 possible paths which will end in 2 different results = 2 unit tests.
Now you can start creating your unit tests but first you need to find out what you need to set up to be able to trigger your code.
private readonly ILogger _logger;
private readonly IInventoryService _inventoryService;
public InventoryServiceBusFunction(ILogger logger, IInventoryService inventoryService)
{
_logger = logger;
_inventoryService = inventoryService;
}
You have some dependencies being passed into your constructor with interfaces - great, this means we can mock them. We want to mock dependencies in unit tests because we want to control their behaviour for the tests. Also, mocking the dependencies negates any "real" behaviour the dependency might be performing i.e. database operations, API calls etc.
Using Moq we can mock the objects like so:
public class InventoryServiceBusFunctionTests
{
private readonly Mock<ILogger> _mockLogger = new Mock<ILogger>();
private readonly Mock<IInventoryService> _mockInventoryService = new Mock<IInventoryService>();
...
We will use these mocks later to make verifications on behaviour we expect to happen.
Next, we need to create an instance of the actual class we want to test.
// using a constructor in the test class will run this code before each test
public InventoryServiceBusFunctionTests()
{
// pass the mocked objects to initialize class
_inventoryServiceBusFunction = new InventoryServiceBusFunction(_mockLogger.Object, _mockInventoryService.Object);
}
Now that we have an instance of the InventoryServiceBusFunction class, we can use any of the public properties/methods in our tests.
[Fact]
public async Task GivenInventoryRequest_WhenFunctionRuns_ThenInventoryServiceProcessesRequest()
{
Now, remembering the paths from earlier, we can start to create the test cases. We can take the first path and create a [Fact] for it. You want to give your test case a meaningful name. I usually use the style of Given_When_Then to describe what is expected to happen.
Next, I usually add 3 comment sections to my test case:
// arrange
// act
// assert
This allows me to clearly see which parts of the test are doing what.
// act
await _inventoryServiceBusFunction.Run(inventoryRequest);
Next, I would fill in the \\ act section because this will tell me (via Intellisense) what I need to arrange. e.g. above, when hovering my mouse over the Run method, I can see that I need to pass an instance of InventoryRequest.
// arrange
var inventoryRequest = new InventoryRequest
{
Name = "abc123",
Quantity = 2,
Tags = new List<string>
{
"foo"
}
};
In the \\ arrange section, initialize an instance of the InventoryRequest class and set the properties. This can be any data as we aren't really interested in the data itself but more what happens when the code runs.
if (inventoryRequest != null)
{
// path 1
await _inventoryService.ProcessRequest(inventoryRequest);
_logger.LogInformation("HBSI Inventory Queue trigger function processed.");
}
Lastly, the \\ assert section. Here, we want to make assertions on what we expect to happen given the set up of the test. So given the InventoryRequest is not null, we expect the if to evaluate to true and we expect the _inventoryService.ProcessRequest(inventoryRequest) method to be executed.
// assert
_mockInventoryService
.Verify(x => x.ProcessRequest(It.Is<InventoryRequest>(ir => ir.Name == inventoryRequest.Name
&& ir.Quantity == inventoryRequest.Quantity
&& ir.Tags.Contains(inventoryRequest.Tags[0]))));
In Moq, we can use the .Verify() method on the mock object to assert that the method was called. We can use the It.Is<T> syntax to make assertions on the data that is passed to the method.
Here is the full test case for path 1:
[Fact]
public async Task GivenInventoryRequest_WhenFunctionRuns_ThenInventoryServiceProcessesRequest()
{
// arrange
var inventoryRequest = new InventoryRequest
{
Name = "abc123",
Quantity = 2,
Tags = new List<string>
{
"foo"
}
};
// act
await _inventoryServiceBusFunction.Run(inventoryRequest);
// assert
_mockInventoryService
.Verify(x => x.ProcessRequest(It.Is<InventoryRequest>(ir => ir.Name == inventoryRequest.Name
&& ir.Quantity == inventoryRequest.Quantity
&& ir.Tags.Contains(inventoryRequest.Tags[0]))));
}
Then for path 2, you are setting up the test so that the else condition is executed.
[Fact]
public async Task GivenInventoryRequestIsNull_WhenFunctionRuns_ThenInventoryServiceDoesNotProcessRequest()
{
// arrange
InventoryRequest inventoryRequest = null;
// act
await _inventoryServiceBusFunction.Run(inventoryRequest);
// assert
_mockInventoryService
.Verify(x => x.ProcessRequest(It.IsAny<InventoryRequest>()), Times.Never);
}
Note - in the \\ assert here, I am asserting that the await _inventoryService.ProcessRequest(inventoryRequest) method is never called. This is because you want the test to fail in this scenario as the method should only be executed in the if condition. You may also choose to verify that the logger method is called with the correct message.
We have WCF services (web hosted in IIS) separatd by domains. We added some claim based security by adding ClaimsAuthorizationManager and overriding the CheckAccess method. Basicaly, we check if the ClaimsPrincipal have the permission needed to execute the method.
Inside the service method :
public DemandePaeDto ObtenirInfoDemandePAE(int idPreDemande, int numeroSequencePreDemande)
{
if (!ClaimsPrincipal.Current.CheckAccess(Management, "DoSomething"))
return null;
Inside the ClaimsAuthorizationManager :
public class FacadeClaimsAuthorizationManager : ClaimsAuthorizationManager
{
public override bool CheckAccess(AuthorizationContext context)
{
var user = context.Principal;
var resource = context.Resource.First().Value;
foreach (var action in context.Action)
{
switch (resource)
{
case "Management":
case "Sales":
case "Product":
if (user.HasClaim(OurOwnCustomClaimTypes.Permission, action.Value))
{
return true;
}
break;
//Pour les cas non gérés
default:
return false;
}
}
return false;
}
}
The problem is when we need to test the services functionalities with WCF Storm of other test tool, we don't have the claims because we set the security mode to false. So we would like to add a custom parameter to all calls. That way we'd be able to bypass by returning true in the CheckAccess method. I've think about MessageInpectors, but still am wondering if it's the right approach. I wouldn't like to add the param to the contracts, because I'd have to modify every call in the application.
Do you have a suggestion ?
You will need to use a different ClaimsAuthorizationManager for your tests. Just derive a different version and use that in your testing environment. It could return true on all call for example.
I'm using WCF custom Validator with HTTPS (.NET 4.5). Validate on success returns Customer object which I would like to use later. Currently I'm able to do it with Static variables which I like to avoid if possible. I tried to use HttpContext which becomes null in main thread. My understanding Validate runs under different thread. Is there any way I could share session info without involving DB or File share. See related threads here and here.
In Authentication.cs
public class CustomValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
//If User Valid then set Customer object
}
}
In Service.cs
public class Service
{
public string SaveData(string XML)
{
//Need Customer object here. Without it cannot save XML.
//HttpContext null here.
}
}
I can suggest you an alternative approach. Assuming that the WCF service is running in ASP.Net compatibility mode and you are saving the customer object to session storage. Create a class such as AppContext
The code would look something like this
public class AppContext {
public Customer CurrentCustomer {
get {
Customer cachedCustomerDetails = HttpContext.Current.Session[CUSTOMERSESSIONKEY] as Customer;
if (cachedCustomerDetails != null)
{
return cachedCustomerDetails;
}
else
{
lock (lockObject)
{
if (HttpContext.Current.Session[CUSTOMERSESSIONKEY] != null) //Thread double entry safeguard
{
return HttpContext.Current.Session[CUSTOMERSESSIONKEY] as Customer;
}
Customer CustomerDetails = ;//Load customer details based on Logged in user using HttpContext.Current.User.Identity.Name
if (CustomerDetails != null)
{
HttpContext.Current.Session[CUSTOMERSESSIONKEY] = CustomerDetails;
}
return CustomerDetails;
}
}
}
}
The basic idea here is to do lazy loading of data, when both WCF and ASP.Net pipelines have executed and HTTPContext is available.
Hope it helps.
Alright this should have been easier. Since the way UserNamePasswordValidator works, I needed to use custom Authorization to pass UserName/Password to the main thread and get customer info again from the database. This is an additional DB call but acceptable workaround for now. Please download code from Rory Primrose's genius blog entry.
Hello can anyone give me advice on how to test my service layer which uses NHibernate ISession directly?
public class UserAccountService : IUserAccountService
{
private readonly ISession _session;
public UserAccountService(ISession session)
{
_session = session;
}
public bool ValidateUser(string email, string password)
{
var value = _session.QueryOver<UserInfo>()
.Select(Projections.RowCount()).FutureValue<int>().Value;
if (value > 0) return true;
return false;
}
}
I opt to use NHibernate directly for simple cases like simple query,validations and creating/updating records in the database. Coz i dont want to have an abstraction like repository/dao layer on top of Nhibernate that will just add more complexity to my architecture.
You need to decide what you want to actually test on your Service Layer, regardless of the fact that you're using NH.
In your example, a good first test might be to test that the email and password that you pass into your service method is actually being used as a check in your session.
In this case, you'd simply need to stub your session variable and set up expectations using a mock framework of some kind (like Rhino Mocks) that would expect a pre-determined email and password, and then return an expected result.
Some pseudocode for this might look like:
void ValidateUser_WhenGivenGoodEmailAndPassword_ReturnsTrue()
{
//arrange
var stubbedSession = MockRepository.GenerateStub<ISession>();
stubbedSession
.Expect(x => x.Query<UserInfo>())
.Return(new List {
new UserInfo { Email = "johns#email.com", Password = "whatever" } });
var service = new UserAccountService(stubbedSession);
//act
var result = service.ValidateUser("johns#email.com", "whatever");
//assert
Assert.That(result, Is.True);
}
I think you'll find it difficult to test database interactions in a static way. I'd recommend delegating responsibilities to another layer (that layer that adds complexity that you mentioned) that can be mocked for testing purposes, if you deem the functionality important enough to test.
I am having a minor problem with WCF service proxies where the message contains List<string> as a parameter.
I am using the 'Add Service reference' in Visual Studio to generate a reference to my service.
// portion of my web service message
public List<SubscribeInfo> Subscribe { get; set; }
public List<string> Unsubscribe { get; set; }
These are the generated properties on my MsgIn for one of my web methods.
You can see it used ArrayOfString when I am using List<string>, and the other takes List<SubscribeInfo> - which matches my original C# object above.
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public System.Collections.Generic.List<DataAccess.MailingListWSReference.SubscribeInfo> Subscribe {
get {
return this.SubscribeField;
}
set {
if ((object.ReferenceEquals(this.SubscribeField, value) != true)) {
this.SubscribeField = value;
this.RaisePropertyChanged("Subscribe");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
publicDataAccess.MailingListWSReference.ArrayOfString Unsubscribe {
get {
return this.UnsubscribeField;
}
set {
if ((object.ReferenceEquals(this.UnsubscribeField, value) != true)) {
this.UnsubscribeField = value;
this.RaisePropertyChanged("Unsubscribe");
}
}
}
The ArrayOfString class generated looks like this. This is a class generated in my code - its not a .NET class. It actually generated me a class that inherits from List, but didn't have the 'decency' to create me any constructors.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.CollectionDataContractAttribute(Name="ArrayOfString", Namespace="http://www.example.com/", ItemName="string")]
[System.SerializableAttribute()]
public class ArrayOfString : System.Collections.Generic.List<string> {
}
The problem is that I often create my message like this :
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.ToList()
});
I really like the clean look this gives me.
Now for the actual problem :
I cant assign a List<string> to the Unsubscribe property which is an ArrayOfString - even though it inherits from List. In fact I cant seem to find ANY way to assign it without extra statements.
I've tried the following :
new ArrayOfString(unsubscribeFrom.ToList()) - this constructor doesn't exist :-(
changing the type of the array used by the code generator - doesn't work - it always gives me ArrayOfString (!?)
try to cast List<string> to ArrayOfString - fails with 'unable to cast', even though it compiles just fine
create new ArrayOfString() and then AddRange(unsubscribeFrom.ToList()) - works, but I cant do it all in one statement
create a conversion function ToArrayOfString(List<string>), which works but isn't as clean as I want.
Its only doing this for string, which is annoying.
Am i missing something? Is there a way to tell it not to generate ArrayOfString - or some other trick to assign it ?
Any .NET object that implements a method named "Add" can be initialized just like arrays or dictionaries.
As ArrayOfString does implement an "Add" method, you can initialize it like this:
var a = new ArrayOfString { "string one", "string two" };
But, if you really want to initialize it based on another collection, you can write a extension method for that:
public static class U
{
public static T To<T>(this IEnumerable<string> strings)
where T : IList<string>, new()
{
var newList = new T();
foreach (var s in strings)
newList.Add(s);
return newList;
}
}
Usage:
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.To<ArrayOfString>()
});
I prefer not to return generic types across a service boundary in the first place. Instead return Unsubscribe as a string[], and SubscriptionInfo as SubscriptionInfo[]. If necessary, an array can easily be converted to a generic list on the client, as follows:
Unsubscribe = new List<string>(unsubscribeFrom);
Subscribe = new List<SubscriptionInfo>(subscribeTo);
Too late but can help people in the future...
Use the svcutil and explicitly inform the command line util that you want the proxy class to be serialized by the XmlSerializer and not the DataContractSerializer (default). Here's the sample:
svcutil /out:c:\Path\Proxy.cs /config:c:\Path\Proxy.config /async /serializer:XmlSerializer /namespace:*,YourNamespace http://www.domain.com/service/serviceURL.asmx
Note that the web service is an ASP.NET web service ok?!
If you are using VS 2008 to consume service then there is an easy solution.
Click on the "Advanced..." button on the proxy dialog that is displayed when you add a Service Reference. In the Collection Type drop down you can select System.Generic.List. The methods returning List should now work properly.
(Hope this is what you were asking for, I'm a little tired and the question was a tad difficult for me to read.)