I am using FluentAssertions (v6.2.0) to test API's that return table-like data. I want to change comparison behavior for one of the field, and tried to use method described in documentation.
orderDto.Should().BeEquivalentTo(order, options => options
.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation, 1.Seconds()))
.When(info => info.Name == "Date"));
The issue is that IMemberInfo class that When extension method is expecting doesn't have Name property, it has property called Path. Was Name replaced by Path and this is a typo in documentation, or do I need to import another namespace to use Name property?
From a quick look at the FluentAssertions source code, I'm seeing that the info argument is of type IObjectInfo and it has a Path property. A quick test with this code shows the Path property working as you would expect:
void Main()
{
var orderDto = new OrderDto { Date = DateTime.Now };
var order = new Order { Date = DateTime.Now };
//var order = new Order { Date = DateTime.Now.Subtract(TimeSpan.FromSeconds(2)) };
orderDto.Should().BeEquivalentTo(order, options => options
.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation, 1.Seconds()))
.When(info => info.Path == "Date"));
}
class OrderDto {
public DateTime Date { get; set; }
}
class Order
{
public DateTime Date { get; set; }
}
In fact, the FluentAssertions test for that code also uses path. See https://github.com/fluentassertions/fluentassertions/blob/master/Tests/FluentAssertions.Specs/Equivalency/ExtensibilityRelatedEquivalencySpecs.cs#L394
There is also an IMethodInfo interface with both Name and Path properties. However, that is used by the Include* and Exclude* methods.
So it appears to be a documentation bug.
Related
public class Details
{
public int Id { get; internal set; }
public string Name { get; set; }
}
I have a task where a setter in a model has an internal attribute and I have tried adding stuff like
[assembly: InternalsVisibleTo("sometestrepo")]
over the model class but to no avail. I googled for a couple of hours and I can't seem to find an answer. Is it even possible to xunit test it or mock and object so that it would allow to create an object with an Id. Otherwise how else am I supposed to fully test CRUD methods that are all based around ID parameter?
The solution is to make private members that you want to test internal.
then you can add InternalsVisibleTo attribute.
[assembly: InternalsVisibleTo("sometestrepo")]
if you're using Moq,You can use something like that:-
var mockAddress = new Mock<Details>();
mockAddress.SetupGet(p => p.Id).Returns(42);
mockAddress.SetupGet(p => p.Name).Returns("Whatever you want to match");
var mockAddressRepository = new Mock<IRepository<Details>>();
var addresses = new List<Details> { mockAddress.Object };
mockAddressRepository.Setup(p => p.GetEnumerator()).Returns(addresses.GetEnumerator());
var addressToMatch = mockAddressRepository.Object.FirstOrDefault(address => address.Id == 42);
Console.WriteLine(addressToMatch.Name);
Expected Output Is:-
Whatever you want to match
One solution that might work is to use a fake.
In your Test class create a fake Details class, inheriting from Details. Then you could new up the property.
public class FakeDetails : Details
{
public new int Id { get; set; }
}
You could use the fake in your test then to set the properties.
var fakeDetails = new FakeDetails();
fakeDetails.Id = 15;
fakeDetails.Name = "Some Name";
I'm having some problems working out how to get Automapper 4.2.1 to allow for a type mapping where the destination value might be null depending on the source value.
Older versions of Automapper allowed an AllowNullDestination flag to be set via the Mapper configuration but I can't find the equivalent recipe for the new version and the old mechanism of configuring via the static Mapper object seems to have been obsoleted.
I have tried the following without success:
Mapper.Configuration.AllowNullDestinationValues = true;
Mapper.AllowNullDestinationValues = true;
Mapper.Initialize(c=>c.AllowNullDestinationValues=true);
Here's a simple test case demonstrating the problem. This fails on the final line with an AutoMapperMappingException since the Substitute method is returning null. I would like both mappings to succeed.
I would prefer to avoid the use of .ForMember in the solution since in the real scenario I'm trying to address, the mapping between bool and 'object' (actually a custom class) should apply across the entire object tree.
Although there are several similar questions here on StackOverflow, I haven't found one that refers to a recent version of Automapper.
Thanks in advance for any suggestions
using AutoMapper;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace AutoMapperTest
{
[TestClass]
public class ExampleTest
{
[TestMethod]
public void NullDestinationCanBeMapped()
{
var mapper = new MapperConfiguration(configuration =>
{
configuration.CreateMap<Source, Target>();
//How should the following mapping be modified to pass the test?
configuration.CreateMap<bool, object>()
.Substitute(i => i ? null : new object());
}).CreateMapper();
var target1 = mapper.Map<Source, Target>(new Source {Member = false}); //succeeds
Assert.IsNotNull(target1.Member); //pass
var target2 = mapper.Map<Source, Target>(new Source {Member = true}); //fails to map with exception
Assert.IsNull(target2.Member); //not reached
}
}
public class Source
{
public bool Member { get; set; }
}
public class Target
{
public object Member { get; set; }
}
}
Instead of using Substitute, use ConvertUsing...
configuration.CreateMap<bool, MyClass>()
.ConvertUsing(i => i ? null : new object());
I've got a small integration service which recieves XML files and parses it.
Also I've created classes from provided XSD for deserializing XML data. During parsing I need to copy properties from those XSD-generated classes to my own that I use in Data Layer. This is an example of my aproach
var supplierInfo = new SupplierInfo();
//coping properties
supplierInfo.Name = supplier.name;
supplierInfo.ShortName = supplier.shortName;
supplierInfo.BrandName = supplier.brandName;
supplierInfo.AdditionalFullName = supplier.additionalFullName;
supplierInfo.AdditionalCode = supplier.additionalCode;
supplierInfo.AdditionalInfo = supplier.additionalInfo;
//lot's of other properties
//...
supplierInfo.Tax = supplier.tax;
supplierInfo.RegistrationDate = supplier.registrationDate;
Some times ammount of properties is very big. Is there more eligant way to copy those properties?
Automapper has been out there since ages ago. Tried and tested. http://automapper.org/
Here's an example:
using System;
using AutoMapper;
public class Program
{
class SupplierInfo
{
public SupplierInfo( string name, string shortName, string brandName ) {
Name = name;
ShortName = shortName;
BrandName = brandName;
}
public string Name {get; private set; }
public string ShortName {get; private set; }
public string BrandName {get; private set; }
}
class Supplier
{
public string name {get; set; }
public string shortName {get; set; }
public string brandName {get; set; }
}
public static void Main()
{
var dto = new Supplier() {
name = "Name 1",
shortName = "Short Name 1",
brandName = "Brand Name 1"
};
//From the tutorial:
//You only need one MapperConfiguration instance typically per AppDomain and should be instantiated during startup.
var config = new MapperConfiguration(cfg => cfg.CreateMap<Supplier, SupplierInfo>());
var mapper = config.CreateMapper();
SupplierInfo info = mapper.Map<SupplierInfo>(dto);
Console.WriteLine( info.Name );
Console.WriteLine( info.ShortName );
Console.WriteLine( info.BrandName );
}
}
The official Getting Started guide can be found at https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
I am happy to be corrected on this but I always find automapper (as per the other answer), which maps property values by name/convention, a little scary to use in production code.
I don't really have a decent alternative but I prefer to do it manually as per your code sample - it's easier to read and debug and if you end up renaming any properties in a class, it will be clear that the copying code is broken (or if you use some IDE tool to rename the property, it'll change the copy code accordingly).
First, install EntityLite.Core:
PM> Install-Package EntityLite.Core
Then use it:
using inercya.EntityLite.Extensions;
...
supplierInfo.AssignPropertiesFrom(supplier);
EntityLite is a micro ORM I developed. It has some little gems :-)
EDIT:
I guess you may not want to install EntityLite.Core just to copy some properties from an object to another. So here you have an implementation of AssignPropertiesFrom extension method that uses Reflection:
public static class ObjectExtensions
{
public static void AssignPropertiesForm(this object target, object source)
{
if (target == null || source == null) throw new ArgumentNullException();
var targetPropertiesDic = target.GetType().GetProperties().Where(p => p.CanWrite).ToDictionary(p => p.Name, StringComparer.CurrentCultureIgnoreCase);
foreach (var sourceProp in source.GetType().GetProperties().Where(p => p.CanRead))
{
PropertyInfo targetProp;
if (targetPropertiesDic.TryGetValue(sourceProp.Name, out targetProp))
{
targetProp.SetValue(target, sourceProp.GetValue(source, null), null);
}
}
}
}
Incidentally, this is not the EntityLite implementation. EntityLite uses dynamic IL generation.
I'm having some issues the using FluentValidation library.
I have a very small Model
`
[FluentValidation.Attributes.Validator(typeof(PersonValidator))]
public class PersonModel
{
public string Name { get; set; }
public Nullable<short> Type { get; set; }
}
`
Have a validator class
public class PersonValidator : AbstractValidator<PersonModel>
{
public PersonValidator()
{
RuleFor(x => x.Name)
.Length(1, 5)
.WithLocalizedMessage(() => BaseValidationResource.LengthValidationMessage, 1, 5);
}
}
And I have a controller
public ActionResult Index()
{
var model = new PersonModel();
model.Name = "John Doe";
var validator = new PersonValidator();
var results = validator.Validate(model);
var error = GetModelErrors();
return View(model);
}
So far so good, the issue is that when the progam is executing and it gets to the line with ; var results = validator.Validate(model); it throws a SystemFormatException.
Instead of throwing an exception, shouldn't the validate method just return an object containing a boolean field which indicates if the model is valid and a list of errors.
PS : I know that this particular validation can also be done using DataAnnotations but i want to use Fluentvalidation because its more flexible.
Thanks in advance for your help.
As #RIc pointed out was a string formatting issue on my Resource file.
On my validor i had this line
RuleFor(x => x.Name)
.Length(1, 5)
.WithLocalizedMessage(() => BaseValidationResource.LengthValidationMessage, 1, 5);
Which pointed to the resource file and passed 2 parameters. But on my resource file i was expecting 3 parameters (property name, min value, max value).
However i was using the wrong annotation. Below are the before and after version of the the resource file.
Note: I'm using the MongoDB C# Driver 2.0
I would like to replicate the behaviour of the BsonConstructor attribute but using the BsonClassMap API.
Something like this:
BsonClassMap.RegisterClassMap<Person>(cm =>
{
cm.AutoMap();
cm.MapCreator(p => new Person(p.FirstName, p.LastName));
});
but without having to specify each argument.
The reason I want to do it this way is that I don't want to "pollute" my domain model with implementation concerns.
I have found this (SetCreator)
BsonClassMap.RegisterClassMap<Person>(cm =>
{
cm.AutoMap();
cm.SetCreator(what goes here?);
});
but I don't know how to use the SetCreator function, and if it does what I think it does...
I achived the same result using the conventions instead of BsonClassMap
Here is an example (reading (serialization) from read only public properties and writing (deserialization) to the constructor)
public class MongoMappingConvention : IClassMapConvention
{
public string Name
{
get { return "No use for a name"; }
}
public void Apply(BsonClassMap classMap)
{
var nonPublicCtors = classMap.ClassType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
var longestCtor = nonPublicCtors.OrderByDescending(ctor => ctor.GetParameters().Length).FirstOrDefault();
classMap.MapConstructor(longestCtor);
var publicProperties = classMap.ClassType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead);
foreach (var publicProperty in publicProperties)
{
classMap.MapMember(publicProperty);
}
}
}
Old question, I know, but something like this worked for me with MongoDB driver 2.10.4:
var mapper = new BsonClassMap(type);
mapper.AutoMap();
var constructorInfo = type.GetConstructor(...); // Find the constructor you want to use
mapper.MapConstructor(constructorInfo, new[] {"FirstName", "LastName"});
Note that the array passed to MapConstructor has the property names, not the constructor argument names. As I understand, it goes by the order of constructor arguments, but they may have different names, e.g.
public Person(string givenName, string surname)
{
FirstName = givenName;
LastName = surname;
}