AutoFixture with derived types - autofixture

In the days before I used AutoFixture, I might have done the following arrangement to set up a unit test of a service called CustomerService:
public void TestName()
{
//Arrange
var fakeResponse = new DerivedHttpResponse();
var fakeHandler = new FakeHttpMessageHandler(fakeResponse); // takes HttpResponse
var httpClient = new HttpClient(fakeHandler);
var sut = new CustomerService(httpClient);
// ...
}
This lengthy arrangement seems like a problem that AutoFixture is good at solving. I'd imagine that I'd be able to rewrite that arrangement using AutoFixture too look something like this:
public void TestName([Frozen] DerivedHttpResponse response, CustomerService sut)
{
//Nothing to arrange
// ...
}
My question is, is there a way to configure AutoFixture to do this for me, given the fact that I have many derived HttpResponse types that I want to swap out from test method to test method?

You can use the [Frozen] attribute with the named parameter As:
[Theory, AutoData]
public void TestName(
[Frozen(As = typeof(HttpResponse))] DerivedHttpResponse response,
CustomerService sut)
{
// 'response' is now the same type, and instance,
// with the type that the SUT depends on.
}
The named parameter As specifies the type that the frozen parameter value should be mapped to.
If the HttpResponse type is abstract you will have to create an AutoDataAttribute derived type e.g. AutoWebDataAttribute
public class AutoWebDataAttribute : AutoDataAttribute
{
public AutoWebDataAttribute()
: base(new Fixture().Customize(new WebModelCustomization()))
{
}
}
public class WebModelCustomization : CompositeCustomization
{
public WebModelCustomization()
: base(
new AutoMoqCustomization())
{
}
}
In that case you would use the [AutoWebData] instead.

Related

Register custom ISpecimenBuilder only to a particular type

I have a custom specimen builder for AutoFixture that omits requests for anonymous values in properties based on the type of the property being requested.
public class PropertyTypeExclusion<T> : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var propertyInfo = request as PropertyInfo;
if (propertyInfo?.PropertyType == typeof(T))
{
return new OmitSpecimen();
}
return new NoSpecimen();
}
}
I can add the customization to the fixture no problem, and it works as expected.
_fixture.Customizations.Add(new PropertyTypeExclusion<IdentityRef>());
Now I want this exclusion to be registered to requests for a specific type. Something like this:
_fixture.Customize<Release>(c => new PropertyTypeExclusion<IdentityRef>());
While the use of .Customize<Release> is valid, it has the same outcome as the call to .Customizations.Add.
Is there a way to register this ISpecimenBuilder only to a specific requested type?
If I understand you correctly, you'd like to be able to do smth like this:
fixture.Create<Release>(); // the `IdentityRef` prop is omitted
fixture.Create<SomeOtherType>(); // the `IdentityRef` prop is NOT omitted
Ok, let's look on this statement:
While the use of .Customize is valid, it has the same outcome as the call to .Customizations.Add
... meaning that even if you register the customization for the Release type only, the other types are impacted as well:
fixture.Customize<Release>(c => new PropertyTypeExclusion<IdentityRef>());
fixture.Create<Release>(); // the `IdentityRef` prop is omitted which is OK
fixture.Create<SomeOtherType>(); // the `IdentityRef` prop is also omitted but it MUST NOT
That sounds like a bug in AF to me and I'd address it here...
As a quick workaround to your issue, you can extend the customization to accept both class and property types to perform more precise filtering:
public class PropertyTypeExclusion<TType, TProp> : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var propertyInfo = request as PropertyInfo;
if (propertyInfo?.PropertyType == typeof(TProp) &&
propertyInfo.DeclaringType == typeof(TType))
{
return new OmitSpecimen();
}
return new NoSpecimen();
}
}
Now:
fixture.Customizations.Add(new PropertyTypeExclusion<Release, IdentityRef>());
fixture.Create<Release>(); // the `IdentityRef` prop is omitted
fixture.Create<SomeOtherType>(); // the `IdentityRef` prop is NOT omitted
To fully re-use the existing AutoFixture's building blocks you could just create a specification:
public class PropertyOfTypeSpecification<TContainer, TProperty> : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
return request is PropertyInfo propertyInfo
&& propertyInfo.PropertyType == typeof(TProperty)
&& propertyInfo.ReflectedType == typeof(TContainer);
}
}
Later you could customize your Fixture as following:
var fixture = new Fixture();
fixture.Customizations.Add(
new Omitter(
new PropertyOfTypeSpecification<Build, IdentityRef>()));

ASP.Net Web Api, POST multiple objects

I have this AngularJS Http Call
$http({
method: "POST",
url: Helper.ApiUrl() + '/Api/Case/SendCase',
data: { obecttype1, obj2, obj3},
}).then(function mySuccess(response) {});
Ant this ASP.net Web Api method
[HttpPost]
[Route("Api/Path/SendCase")]
public int SendCase(object application)
{
string applicantName = ((Newtonsoft.Json.Linq.JObject)application)["applicant"].ToString();
obecttype1 obj = JsonConvert.DeserializeObject<obecttype1>(((Newtonsoft.Json.Linq.JObject)application)["obecttype1"].ToString());
.........................
return ID;
}
This works pretty well, but I feel it is a bit dirty because I am parsing my objects in my method, so my question is
Is the are way to send multiple objects as params in a POST method, I would prefer to avoid modifying my model, avoid creating a class for this
So my Api Method would look like this
public int SendCase(class1 obecttype1, class2 obj2, class3 obj3)
"Is the are way to send multiple objects as params in a POST method, I would prefer to avoid modifying my model, avoid creating a class for this"
By design HTTP Post can only have one body and web api will try to cast the body to the parameter defined in the method signature. So sending multiple objects in the body and trying to match these against multiple params in the method signature will not work. For that you need to define a class which holds the other classes and match the body signature.
public class postDTO
{
public class1 class1Data { get; set; }
public class2 class2Data { get; set; }
public class3 class3Data { get; set; }
}
//The api signature
public int SendCase(postDTO application)
If you still don't want to add the new class then I would use the JObject directly as the parameter as this
[HttpPost]
public int SendCase(JObject jsonData)
{
dynamic json = jsonData;
JObject class1DataJson = json.class1Data;
JObject class2DataJson = json.class2Data;
JObject class3DataJson = json.class3Data;
var class1Data = class1DataJson.ToObject<class1>();
var class2Data = class2DataJson.ToObject<class2>();
var class3Data = class3DataJson.ToObject<class3>();
}
1. Define models for the parameters
public class ClassType1
{
public int Num1 { get; set; }
public string Str1 { get; set; }
}
public class ClassType2
{
public double Test2 { get; set; }
}
2. Use the models as the parameters on the API controller method
// Sorry this example is setup on .Net Core 2.0 but I think the previous
// versions of Web Api would have similar/same behavior
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpPost]
public void Post(ClassType1 ct1, ClassType2 ct2)
{}
}
3. When posting, your objects inside the data {} have to have the keys that match the parameter name you defined on the Controller method
jQuery ajax
$.ajax({
method: 'post',
url: 'http://localhost:53101/api/values',
dataType: 'json',
data: {
// It takes key value pairs
ct1: {
num1: 1,
str1: 'some random string'
},
ct2: {
test2: 0.34
}
}
});
To summarize, yes you can post multiple objects back to the server, as long as
You define a key for each object and the key has to match the parameter name you define on the server method.
The object structure has to match.
-- update --
Just as a proof, here is the screenshot:
We have an app that uses DefaultHttpBatchHandler to accept multi-part POST requests. I believe it to be a bit clunky for many reasons but it is the built-in way to accept multiple objects on a single request in a structured fashion.
https://msdn.microsoft.com/en-us/library/system.web.http.batch.defaulthttpbatchhandler(v=vs.118).aspx
As for the script to create something, that I don't know about. Our callers that use this API are C# services that can create the multi-part requests using a simple client library we provide to help them do just that.

Nancy testing GetModel<T> throws KeyNotFoundException

I'm trying to test that the model returned from my Nancy application is as expected. I have followed the docs here but whenever I call the GetModel<T> extension method it throws a KeyNotFoundException.
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
I know what the error means but I'm failing to see why it's being thrown.
Here's my module
public class SanityModule : NancyModule
{
public SanityModule()
{
Get["sanity-check"] = _ => Negotiate.WithModel(new SanityViewModel { Id = 1 })
.WithStatusCode(HttpStatusCode.OK);
}
}
my view model
public class SanityViewModel
{
public int Id { get; set; }
}
and here's my test
[TestFixture]
public class SanityModuleTests
{
[Test]
public void Sanity_Check()
{
// Arrange
var browser = new Browser(with =>
{
with.Module<SanityModule>();
with.ViewFactory<TestingViewFactory>();
});
// Act
var result = browser.Get("/sanity-check", with =>
{
with.HttpRequest();
with.Header("accept", "application/json");
});
var model = result.GetModel<SanityViewModel>();
// Asset
model.Id.ShouldBeEquivalentTo(1);
}
}
Debugging this test shows that the module is hit and completes just fine. Running the application shows that the response is as expected.
Can anyone shed some light on this?
Thanks to the lovely guys, albertjan and the.fringe.ninja, in the Nancy Jabbr room we've got an explanation as to what's going on here.
TL;DR It makes sense for this to not work but the error message should be more descriptive. There is a workaround below.
The issue here is that I am requesting the response as application/json whilst using TestingViewFactory.
Let's take a look at the implementation of GetModel<T>();
public static TType GetModel<TType>(this BrowserResponse response)
{
return (TType)response.Context.Items[TestingViewContextKeys.VIEWMODEL];
}
This is simply grabbing the view model from the NancyContext and casting it to your type. This is where the error is thrown, as there is no view model in NancyContext. This is because the view model is added to NancyContext in the RenderView method of TestingViewFactory.
public Response RenderView(string viewName, dynamic model, ViewLocationContext viewLocationContext)
{
// Intercept and store interesting stuff
viewLocationContext.Context.Items[TestingViewContextKeys.VIEWMODEL] = model;
viewLocationContext.Context.Items[TestingViewContextKeys.VIEWNAME] = viewName;
viewLocationContext.Context.Items[TestingViewContextKeys.MODULENAME] = viewLocationContext.ModuleName;
viewLocationContext.Context.Items[TestingViewContextKeys.MODULEPATH] = viewLocationContext.ModulePath;
return this.decoratedViewFactory.RenderView(viewName, model, viewLocationContext);
}
My test is requesting json so RenderView will not be called. This means you can only use GetModel<T> if you use a html request.
Workaround
My application is an api so I do not have any views so changing the line
with.Header("accept", "application/json");
to
with.Header("accept", "text/html");
will throw a ViewNotFoundException. To avoid this I need to implement my own IViewFactory. (this comes from the.fringe.ninja)
public class TestViewFactory : IViewFactory
{
#region IViewFactory Members
public Nancy.Response RenderView(string viewName, dynamic model, ViewLocationContext viewLocationContext)
{
viewLocationContext.Context.Items[Fixtures.SystemUnderTest.ViewModelKey] = model;
return new HtmlResponse();
}
#endregion
}
Then it is simply a case of updating
with.ViewFactory<TestingViewFactory>();
to
with.ViewFactory<TestViewFactory>();
Now GetModel<T> should work without needing a view.

Angular and Web Api 2 handling List parameters

I need to take in a collection of MyObject on my webApi controller:
[RoutePrefix("api/DoStuffApi")]
public class DoStuffApiController : ApiController
{
[Route("Update/")]
public HttpStatusCode Update(IEnumerable<MyObject> requests)
{
//DO STUFF
}
}
I would need to use the FromBody parameter attribute to get the list normally:
[Route("Update/")]
public HttpStatusCode Update([FromBody] IEnumerable<MyObject> requests)
{
//DO STUFF
}
Is this better than taking in an object with a collection on it?
[Route("Update/")]
public HttpStatusCode Update(MyRequestObject request)
{
//DO STUFF
}
public class MyRequestObject
{
public IEnumerable<MyObject> requests {get;set;}
}
On the second example I can create a JavaScript object or an Angular module that matches the parameter and pass it into the post call on angular.
.factory('setSomething', [
'$http',
function($http) {
return {
var data = new objectsToUpdate(); //my custom object with an array in it
set: function (customerId) {
return $http.post('api/DoStuffApi/Update/', data);
}
}
}
]);
I cannot find any information on how to do this type of thing. The route attributes follow this article.
This just really depends on what your object you want to post looks like. Do you need to send any other data than the array in the POST? If not then using the former solution would be better since otherwise you are just writing useless additional code for you to maintain. So using the former example would be cleaner.
If however you have more data in your post along with the array you should put it all in a special model class in the controller like you do in your second example..
To have angular POST it correctly so the API model binds to the IEnumerable in the first example, you would simply post the array itself instead of having it inside an object.
function($http) {
return {
var data = new objectsToUpdate(); //my custom object with an array in it
set: function (customerId) {
return $http.post('api/DoStuffApi/Update/', data.nameOfArray); // Don't post the object, just the array
}
}
}
This should bind to the IEnumerable just fine if the fields in the model and the array have the same names.

Register Specific Module Constructor

I would like to inject different strings into each of my module's contructors. I register a factory method which constructs the module. I can then call container.Resolve<T>() and all is well. For some reason though when Nancy tries to resolve my module it throws the error
Nancy.TinyIoc.TinyIoCResolutionException: Unable to resolve type:
Plugin.HomeModule ---> Nancy.TinyIoc.TinyIoCResolutionException:
Unable to resolve type: System.String
public class HomeModule : NancyModule
{
public HomeModule(string text)
{
}
}
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.Register<HomeModule>((ctr, param) => { return new HomeModule("text"); });
HomeModule module = container.Resolve<HomeModule>();
}
I have also tried doing the registration in ConfigureRequestContainer() with the same results. I have tried container.Register<HomeModule>(new HomeModule("some text")); as well as AsSingleton(). I can register an implementation to the string type with container.Register<string>("text"), but this would inject the same string into all modules.
How can I register a module constructor so that Nancy can resolve it?
Modules are obtained through the INancyModuleCatalog, which is normally implemented by the bootstrapper, you'd have to create a custom variation of that - if you're using the default bootstrapper then this is the current implementation:
https://github.com/NancyFx/Nancy/blob/master/src/Nancy/DefaultNancyBootstrapper.cs#L205
The best approach for this would be to not pass in a primitive into your module, but us something richer, or perhaps a factory. The container can resolve those dependencies. Passing a plain string into the module is a sign of a problem somewhere else and a hint that your architecture probably needs rethinking
I have implemented a custom catalog that registeres only Modules of a specific namespace, but I don't know where to register this.
public CustomModuleCatalog()
{
// The license type is read from db in Global.ascx.
// So I want to register a module based on a namespace.
// The namespace is the same like the license name.
if(WebApiApplication.LicenseType == LicenseType.RouteOne)
{
var assemblyTypes = Assembly.GetExecutingAssembly().GetTypes();
var modules = assemblyTypes.Where(t => t.Namespace != null && t.Namespace.EndsWith("MyCustomNamespace"));
var nancy = modules.Where(t => t.IsAssignableFrom(typeof(INancyModule)));
foreach (var type in nancy)
{
var nancyType = (INancyModule)type;
_modules.Add(type, (INancyModule)Activator.CreateInstance(type));
}
}
}
public IEnumerable<INancyModule> GetAllModules(NancyContext context)
{
return _modules?.Values;
}
public INancyModule GetModule(Type moduleType, NancyContext context)
{
if (_modules != null && _modules.ContainsKey(moduleType))
{
return _modules[moduleType];
}
return null;
}

Resources