I wanted to ask about a scenario that happened to me.
I am working with different models that implement a common generic property, which has different implementations, however, this generic property is common.
In this case, I am doing a Mapping where they have a generic property T in common with other models, in the example I created it is Comparable and NonComparable, both implement a Unit T.
Initially, I have a Mapper for comparable and another for IComparable, as you can see:
Code Link: https://github.com/xeof-landmark/generic-tests
Branch: main
Repeating Code Here:
Program
class Program
{
static Fixture fixture = new Fixture();
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var map = new Map();
var unitsComparables = InitializeComparables();
var unitsNonComparables = InitializeNonComparables();
var unitsMappedCompared = map.MapList(unitsComparables);
var unitsMappedNonCompared = map.MapList(unitsNonComparables);
var units = new List<IUnit>();
units.AddRange(unitsMappedCompared);
units.AddRange(unitsMappedNonCompared);
foreach (var unit in units)
{
Console.WriteLine(unit.Name);
Console.WriteLine(Environment.NewLine);
}
}
static List<Comparable<IUnit>> InitializeComparables()
{
return new List<Comparable<IUnit>>()
{
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
};
}
static List<NonComparable<IUnit>> InitializeNonComparables()
{
return new List<NonComparable<IUnit>>()
{
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
};
}
}
Classes:
public class SaleUnit : IUnit
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class LegacyUnit : IUnit
{
public int Id { get; set; }
private string name;
public string Name
{
get { return $"{name}.Legacy"; }
set { name = value; }
}
public string Description { get; set; }
}
public interface IUnit
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class Comparable<T>
where T : IUnit
{
public T Unit { get; set; }
public int ExisingUnit { get; set; }
}
public class NonComparable<T>
where T : IUnit
{
public T Unit { get; set; }
public bool IsDifferent(int id) => true;
public void AddNewPrices(decimal prices) => throw new System.NotImplementedException();
}
Mapper
public class Map
{
static Fixture fixture = new Fixture();
public List<IUnit> MapList(List<Comparable<IUnit>> compareOnes)
{
return new List<IUnit>()
{
fixture.Create<LegacyUnit>(),
fixture.Create<LegacyUnit>(),
fixture.Create<LegacyUnit>(),
fixture.Create<SaleUnit>(),
fixture.Create<SaleUnit>(),
};
}
public List<IUnit> MapList(List<NonComparable<IUnit>> compareOnes)
{
return new List<IUnit>()
{
fixture.Create<LegacyUnit>(),
fixture.Create<LegacyUnit>(),
fixture.Create<LegacyUnit>(),
fixture.Create<SaleUnit>(),
fixture.Create<SaleUnit>(),
};
}
}
I realized that at first, I was repeating a lot of code, in turn, I was reading a bit about covariance (I tried to do it but I couldn't).
I ended up solving it by casting them as an IComparable interface and then using a common Mapper for the IComparables.
Resolution Link: https://github.com/xeof-landmark/generic-tests/pull/1
So I ended up doing this
First I've created a new Interface to abstract the generic Unit.
public interface IComparable<T>
where T : IUnit
{
public T Unit { get; set; }
}
I have inherited the Comparable and NonComparable from IComparable
public class Comparable<T> : IComparable<T>
where T : IUnit
{
public T Unit { get; set; }
public int ExisingUnit { get; set; }
}
public class NonComparable<T> : IComparable<T>
where T : IUnit
{
public T Unit { get; set; }
public bool IsDifferent(int id) => true;
public void AddNewPrices(decimal prices) => throw new System.NotImplementedException();
}
Then I added a new method overload to my Map Class to handle both Comparable and NonComparable MapList(List<IComparable> unitsComparables) to be able to handle both maps.
public List<IUnit> MapList(List<IComparable<IUnit>> unitsComparables)
{
var mapUnitComparables = unitsComparables.Where(x => x is Comparable<IUnit>).Select(s => (Comparable<IUnit>)s).ToList();
var mapUnitNonComparables = unitsComparables.Where(x => x is NonComparable<IUnit>).Select(s => (NonComparable<IUnit>)s).ToList();
var result = new List<IUnit>();
result.AddRange(MapList(mapUnitComparables));
result.AddRange(MapList(mapUnitNonComparables));
return result;
}
And Finally my Program:
class Program
{
static Fixture fixture = new Fixture();
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var map = new Map();
var unitsComparables = InitializeComparables();
var units = map.MapList(unitsComparables);
foreach (var unit in units)
{
Console.WriteLine(unit.Name);
Console.WriteLine(Environment.NewLine);
}
}
static List<IComparable<IUnit>> InitializeComparables()
{
return new List<IComparable<IUnit>>()
{
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
new Comparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<LegacyUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
new NonComparable<IUnit> { Unit = fixture.Create<SaleUnit>() },
};
}
}
Now my question is, this solves it, but .....
Would it be the best way to solve it? or can it be done better?
Could I use covariance on this occasion? is it well planned?
Related
I was trying to implement a code to ignore a property (therefore mantaining the source value). I used the ignore method, which works most of the time. For some reason I noticed that sometimes the ignore sets the property value to null.
Do you know what could be problem?
I created the following code to reproduce the issue. I was expecting client.ContactDetails.First().Address to have the value "Old".
using AutoMapper;
class Program
{
static void Main(string[] args)
{
ClientMapperProfile clientMapperProfile = new ClientMapperProfile();
var configurationProvider = new MapperConfiguration(c => c.AddProfile(clientMapperProfile));
Mapper mapper = new Mapper(configurationProvider);
var client = new Client()
{
ContactDetails = new []
{
new ContactDetails()
{
Address= "Old"
}
}
};
var clientDto = new ClientDto()
{
ContactDetails = new []
{
new ContactDetailsDto()
{
Address = "New"
}
}
};
mapper.Map(clientDto,client);
Console.WriteLine(client.ContactDetails.First().Address);
}
}
public class Client
{
public ContactDetails[] ContactDetails { get; set; }
}
public class ContactDetails
{
public string Address { get; set; }
}
public class ClientDto
{
public ContactDetailsDto[] ContactDetails { get; set; }
}
public class ContactDetailsDto
{
public string Address { get; set; }
}
public class ClientMapperProfile : Profile
{
public ClientMapperProfile()
{
CreateMap<ClientDto, Client>();
CreateMap<ContactDetailsDto, ContactDetails>()
.ForMember(c => c.Address, opt => opt.Ignore());
}
}
I'm wondering if I can do a global config for a test. I know that I can compare this object something like that:
x.Should().BeEquivalentTo(y, opt => opt.Excluding(z => z.Member)
But I want all the methods in my test to use this config.
To exclude a member from a specific type, you can create a custom IMemberSelectionRule.
To use that selection rule for all tests, use the static AssertionOptions.AssertEquivalencyUsing in some setup method of your unit testing framework.
Be aware that AssertionOptions.AssertEquivalencyUsing changes static state of Fluent Assertions, so if you're running tests in parallel it should be invoked before any tests are run.
For NUnit that would be [OneTimeSetUp] inside a [SetUpFixture] not inside a namespace.
using FluentAssertions;
using FluentAssertions.Equivalency;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
[SetUpFixture]
public class MySetUpClass
{
[OneTimeSetUp]
public void RunBeforeAnyTests()
{
AssertionOptions.AssertEquivalencyUsing(e => e.Using(new MyNamespace.MyClassSelectionRule()));
}
}
namespace MyNamespace
{
class MyOuterClass
{
public MyInnerClass MemberToInclude { get; set; }
public int MemberToExclude { get; set; }
}
class MyInnerClass
{
public int AnotherMemberToInclude { get; set; }
public int MemberToExclude { get; set; }
}
internal class MyClassSelectionRule : IMemberSelectionRule
{
public bool IncludesMembers => false;
public IEnumerable<SelectedMemberInfo> SelectMembers(IEnumerable<SelectedMemberInfo> selectedMembers, IMemberInfo context, IEquivalencyAssertionOptions config) =>
selectedMembers.Where(e => !(e.DeclaringType.Name == nameof(MyOuterClass) && e.Name == nameof(MyOuterClass.MemberToExclude)));
}
[TestFixture]
public class UnitTest1
{
[Test]
public void Ignore_the_member_MemberToExclude_on_MyOuterClass()
{
var subject = new MyOuterClass
{
MemberToInclude = new MyInnerClass
{
AnotherMemberToInclude = 42,
MemberToExclude = 42
},
MemberToExclude = 1
};
var expectation = new MyOuterClass
{
MemberToInclude = new MyInnerClass
{
AnotherMemberToInclude = 42,
MemberToExclude = 42
},
MemberToExclude = 2
};
subject.Should().BeEquivalentTo(expectation);
}
[Test]
public void Do_not_ignore_the_member_MemberToExclude_on_MyInnerClass()
{
var subject = new MyOuterClass
{
MemberToInclude = new MyInnerClass
{
MemberToExclude = 1
},
};
var expectation = new MyOuterClass
{
MemberToInclude = new MyInnerClass
{
MemberToExclude = 2
},
};
Action act = () => subject.Should().BeEquivalentTo(expectation);
act.Should().Throw<AssertionException>();
}
}
}
I'm trying to use Microsoft Bond to serialize nested objects. But Bond throws internal errors (such KeyNotFoundException).
My classes:
interface IFoo
{
}
[Bond.Schema]
class Foo1 : IFoo
{
[Bond.Id(0)]
public string Foo1Field { get; set; }
}
[Bond.Schema]
class Bar
{
[Bond.Id(0)]
public IFoo SomeFooInstance { get; set; }
}
Then I create an instance and serialize:
var src = new Bar() { SomeFooInstance = new Foo1() { Foo1Field = "Str" }};
var output = new OutputBuffer();
var writer = new CompactBinaryWriter<OutputBuffer>(output);
Serialize.To(writer, src);
var input = new InputBuffer(output.Data);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = Deserialize<Bar>.From(reader);
But I'm getting exceptions (such KeyNotFoundException) at Serialize.To(writer, src);.
I also tried to add [Bond.Schema] to IFoo, but then the Deserialize<Bar>.From(reader); fails...
How can I serialize Bar class that contains some Foo class with Bond without getting exceptions like that?
If you want to use interfaces with behavioral differences (and not structural differences), the trick is to provide the deserializer with a factory so that it knows how to create a concrete instance of IFoo when it needs to. Notice that the implementations do not have the the [Bond.Schema] attribute, as they both implement the IFoo schema.
namespace NS
{
using System;
using Bond.IO.Unsafe;
using Bond.Protocols;
internal static class Program
{
[Bond.Schema]
interface IFoo
{
[Bond.Id(10)]
string FooField { get; set; }
}
[Bond.Schema]
class Bar
{
[Bond.Id(20)]
public IFoo SomeFooInstance { get; set; }
}
class AlwaysUppercaseFoo : IFoo
{
private string fooField;
public string FooField
{
get
{
return fooField;
}
set
{
fooField = value.ToUpperInvariant();
}
}
}
class IdentityFoo : IFoo
{
public string FooField { get; set; }
}
public static Expression NewAlwaysUppercaseFoo(Type type, Type schemaType, params Expression[] arguments)
{
if (schemaType == typeof(IFoo))
{
return Expression.New(typeof(AlwaysUppercaseFoo));
}
// tell Bond we don't handle the requested type, so it should use it's default behavior
return null;
}
public static Expression NewIdentityFoo(Type type, Type schemaType, params Expression[] arguments)
{
if (schemaType == typeof(IFoo))
{
return Expression.New(typeof(IdentityFoo));
}
// tell Bond we don't handle the requested type, so it should use it's default behavior
return null;
}
public static void Main(string[] args)
{
var src = new Bar() { SomeFooInstance = new IdentityFoo() { FooField = "Str" } };
var output = new OutputBuffer();
var writer = new CompactBinaryWriter<OutputBuffer>(output);
Bond.Serialize.To(writer, src);
{
var input = new InputBuffer(output.Data);
var deserializer = new Bond.Deserializer<CompactBinaryReader<InputBuffer>>(typeof(Bar), NewAlwaysUppercaseFoo);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = deserializer.Deserialize<Bar>(reader);
Debug.Assert(dst.SomeFooInstance.FooField == "STR");
}
{
var input = new InputBuffer(output.Data);
var deserializer = new Bond.Deserializer<CompactBinaryReader<InputBuffer>>(typeof(Bar), NewIdentityFoo);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = deserializer.Deserialize<Bar>(reader);
Debug.Assert(dst.SomeFooInstance.FooField == "Str");
}
}
}
}
If you need both behavioral and structural differences, then you'll need to pair this with polymorphism and a bonded<IFoo> field so that you can delay deserialization until you have enough type information to select the proper implementation. (Polymorphism is explicit and opt-in in Bond.)
I'd show an example of this, but while writing up this answer on 2018-02-21, I found a bug in the handling of classes with [Bond.Schema] that implement interfaces with [Bond.Schema]: the fields from the interface are omitted.
For now, the workaround would be to use inheritance with classes and use virtual properties. For example:
namespace NS
{
using System;
using Bond.IO.Unsafe;
using Bond.Protocols;
internal static class Program
{
enum FooKind
{
Unknown = 0,
AlwaysUppercase = 1,
Identity = 2,
}
// intentionally a class to work around https://github.com/Microsoft/bond/issues/801 but simulate an interface somewhat
[Bond.Schema]
class IFoo
{
[Bond.Id(0)]
public virtual string FooField { get; set; }
}
[Bond.Schema]
class Bar
{
[Bond.Id(0)]
public Bond.IBonded<IFoo> SomeFooInstance { get; set; }
[Bond.Id(1)]
public FooKind Kind { get; set; }
}
[Bond.Schema]
class AlwaysUppercaseFoo : IFoo
{
private string fooField;
public override string FooField
{
get
{
return fooField;
}
set
{
fooField = value.ToUpperInvariant();
}
}
[Bond.Id(0)]
public string JustAlwaysUppercaseFooField { get; set; }
}
[Bond.Schema]
class IdentityFoo : IFoo
{
[Bond.Id(42)]
public string JustIdentityFooField { get; set; }
}
static void RoundTripAndPrint(Bar src)
{
var output = new OutputBuffer();
var writer = new CompactBinaryWriter<OutputBuffer>(output);
Bond.Serialize.To(writer, src);
var input = new InputBuffer(output.Data);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = Bond.Deserialize<Bar>.From(reader);
switch (dst.Kind)
{
case FooKind.Identity:
{
var fooId = dst.SomeFooInstance.Deserialize<IdentityFoo>();
Console.WriteLine($"IdFoo: \"{fooId.FooField}\", \"{fooId.JustIdentityFooField}\"");
}
break;
case FooKind.AlwaysUppercase:
{
var fooUc = dst.SomeFooInstance.Deserialize<AlwaysUppercaseFoo>();
Console.WriteLine($"UcFoo: \"{fooUc.FooField}\", \"{fooUc.JustAlwaysUppercaseFooField}\"");
}
break;
default:
Console.WriteLine($"Unknown Kind: {dst.Kind}");
break;
}
}
public static void Main(string[] args)
{
var o = new OutputBuffer();
var w = new CompactBinaryWriter<OutputBuffer>(o);
Bond.Serialize.To(w, new IdentityFoo() { FooField = "Str", JustIdentityFooField = "id" });
var src_id = new Bar()
{
SomeFooInstance = new Bond.Bonded<IdentityFoo>(new IdentityFoo() { FooField = "Str", JustIdentityFooField = "id" }),
Kind = FooKind.Identity
};
var src_uc = new Bar()
{
SomeFooInstance = new Bond.Bonded<AlwaysUppercaseFoo>(new AlwaysUppercaseFoo() { FooField = "Str", JustAlwaysUppercaseFooField = "I LIKE TO YELL!" }),
Kind = FooKind.AlwaysUppercase
};
RoundTripAndPrint(src_id);
RoundTripAndPrint(src_uc);
}
}
}
This prints:
IdFoo: "Str", "id"
UcFoo: "STR", "I LIKE TO YELL!"
I'm working on a project where I have some recursive data structure and I want to create a fixture for it.
The data structure is XmlCommandElement, it has a single method ToCommand that converts XmlCommandElement to Command.
Each node on the tree can be a XmlCommandElement and/or XmlCommandPropertyElement.
Now, in order to test the behaviour of the method ToCommand I want to fetch XmlCommandElement with some arbitrary data.
I want to control the depth of the tree and the amount of instances of XmlCommandElement and/or XmlCommandPropertyElement per node.
So here is the code I'm using for the fixture:
public class XmlCommandElementFixture : ICustomization
{
private static readonly Fixture _fixture = new Fixture();
private XmlCommandElement _xmlCommandElement;
public int MaxCommandsPerDepth { get; set; }
public int MaxDepth { get; set; }
public int MaxPropertiesPerCommand { get; set; }
public XmlCommandElementFixture BuildCommandTree()
{
_xmlCommandElement = new XmlCommandElement();
var tree = new Stack<XmlCommandElementNode>();
tree.Push(new XmlCommandElementNode(0, _xmlCommandElement));
while (tree.Count > 0) {
var node = tree.Pop();
node.Command.Key = CreateRandomString();
node.Command.Properties = CreateProperties();
if (MaxDepth > node.Depth) {
var commands = new List<XmlCommandElement>();
for (var i = 0; i < MaxCommandsPerDepth; i++) {
var command = new XmlCommandElement();
tree.Push(new XmlCommandElementNode(node.Depth + 1, command));
commands.Add(command);
}
node.Command.Commands = commands.ToArray();
}
}
return this;
}
public void Customize(IFixture fixture)
{
fixture.Customize<XmlCommandElement>(c => c.FromFactory(() => _xmlCommandElement)
.OmitAutoProperties());
}
private static string CreateRandomString()
{
return _fixture.Create<Generator<string>>().First();
}
private XmlCommandPropertyElement[] CreateProperties()
{
var properties = new List<XmlCommandPropertyElement>();
for (var i = 0; i < MaxPropertiesPerCommand; i++) {
properties.Add(new XmlCommandPropertyElement {
Key = CreateRandomString(),
Value = CreateRandomString()
});
}
return properties.ToArray();
}
private struct XmlCommandElementNode
{
public XmlCommandElementNode(int depth, XmlCommandElement xmlCommandElement)
{
Depth = depth;
Command = xmlCommandElement;
}
public XmlCommandElement Command { get; }
public int Depth { get; }
}
}
And this is how I'm using it:
xmlCommandElement = new Fixture().Customize(new XmlCommandElementFixture {
MaxDepth = 2,
MaxCommandsPerDepth = 3,
MaxPropertiesPerCommand = 4
}.BuildCommandTree()).Create<XmlCommandElement>();
This works perfectly fine! but the issue I have with it is it isn't generic, the whole point of AutoFixture at least as far as I know is to avoid making specific fixtures.
So what I would really like to do is something like this (found it here but it doesn't work for me.):
var fixture = new Fixture();
fixture.Behaviors.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new DepthThrowingRecursionBehavior(2));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(XmlCommandElement), 3));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(XmlCommandPropertyElement), 4));
xmlCommandElement = fixture.Create<XmlCommandElement>();
Here is all the code for reference:
Interfaces:
public interface ICommandCollection : IEnumerable<ICommand>
{
ICommand this[string commandName] { get; }
void Add(ICommand command);
}
public interface ICommandPropertyCollection : IEnumerable<ICommandProperty>
{
string this[string key] { get; }
void Add(ICommandProperty property);
}
public interface ICommandProperty
{
string Key { get; }
string Value { get; }
}
public interface ICommand
{
ICommandCollection Children { get; set; }
string Key { get; }
ICommandPropertyCollection Properties { get; }
}
public interface ICommandConvertible
{
ICommand ToCommand();
}
Classes:
public sealed class CommandPropertyCollection : ICommandPropertyCollection
{
private readonly IDictionary<string, ICommandProperty> _properties;
public CommandPropertyCollection()
{
_properties = new ConcurrentDictionary<string, ICommandProperty>();
}
public string this[string key]
{
get
{
ICommandProperty property = null;
_properties.TryGetValue(key, out property);
return property.Value;
}
}
public void Add(ICommandProperty property)
{
_properties.Add(property.Key, property);
}
public IEnumerator<ICommandProperty> GetEnumerator()
{
return _properties.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public sealed class CommandProperty : ICommandProperty
{
public CommandProperty(string key, string value)
{
Key = key;
Value = value;
}
public string Key { get; }
public string Value { get; }
}
public sealed class Command : ICommand
{
public Command(string key, ICommandPropertyCollection properties)
{
Key = key;
Properties = properties;
}
public ICommandCollection Children { get; set; }
public string Key { get; }
public ICommandPropertyCollection Properties { get; }
}
public class XmlCommandPropertyElement : ICommandPropertyConvertible
{
[XmlAttribute("key")]
public string Key { get; set; }
[XmlAttribute("value")]
public string Value { get; set; }
public ICommandProperty ToCommandProperty()
{
return new CommandProperty(Key, Value);
}
}
Finally, the class I'm trying to test is as follow:
public class XmlCommandElement : ICommandConvertible
{
[XmlArray]
[XmlArrayItem("Command", typeof(XmlCommandElement))]
public XmlCommandElement[] Commands { get; set; }
[XmlAttribute("key")]
public string Key { get; set; }
[XmlArray]
[XmlArrayItem("Property", typeof(XmlCommandPropertyElement))]
public XmlCommandPropertyElement[] Properties { get; set; }
public ICommand ToCommand()
{
ICommandPropertyCollection properties = new CommandPropertyCollection();
foreach (var property in Properties) {
properties.Add(property.ToCommandProperty());
}
ICommand command = new Command(Key, properties);
return command;
}
}
The test itself looks like this:
namespace Yalla.Tests.Commands
{
using Fixtures;
using FluentAssertions;
using Ploeh.AutoFixture;
using Xbehave;
using Yalla.Commands;
using Yalla.Commands.Xml;
public class XmlCommandElementTests
{
[Scenario]
public void ConvertToCommand(XmlCommandElement xmlCommandElement, ICommand command)
{
$"Given an {nameof(XmlCommandElement)}"
.x(() =>
{
xmlCommandElement = new Fixture().Customize(new XmlCommandElementFixture {
MaxDepth = 2,
MaxCommandsPerDepth = 3,
MaxPropertiesPerCommand = 4
}.BuildCommandTree()).Create<XmlCommandElement>();
});
$"When the object is converted into {nameof(ICommand)}"
.x(() => command = xmlCommandElement.ToCommand());
"Then we need to have a root object with a key"
.x(() => command.Key.Should().NotBeNullOrEmpty());
"And 4 properties as its children"
.x(() => command.Properties.Should().HaveCount(4));
}
}
}
Thanks to Mark Seemann! the final solution looks like this:
public class RecursiveCustomization : ICustomization
{
public int MaxDepth { get; set; }
public int MaxElements { get; set; }
public void Customize(IFixture fixture)
{
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(MaxDepth));
fixture.RepeatCount = MaxElements;
}
}
And can be used like this:
xmlCommandElement = new Fixture().Customize(new RecursiveCustomization {
MaxDepth = 2,
MaxElements = 3
}).Create<XmlCommandElement>();
You can fairly easily create a small tree by changing the Fixture's recursion behaviour:
[Fact]
public void CreateSmallTree()
{
var fixture = new Fixture();
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(recursionDepth: 2));
var xce = fixture.Create<XmlCommandElement>();
Assert.NotEmpty(xce.Commands);
}
The above test passes.
Below codes run perfectly but i want to re generate simply
static void YeniMethodListele()
{
Calısan calisan = new Calısan(){ ID=1, Ad="xxx", SoyAd="yyy"};
List<Calısan> myList = new List<Calısan>();
myList.Add(calisan);
MyCalısan myCalısan = new MyCalısan() { list = myList };
//myCalısan.list.Add(calisan);
foreach (Calısan item in myCalısan.list)
{
Console.WriteLine(item.Ad.ToString());
}
}
}
public class Calısan
{
public int ID { get; set; }
public string Ad { get; set; }
public string SoyAd { get; set; }
}
public class MyCalısan
{
public List<Calısan> list { get; set; }
public MyCalısan()
{
list = new List<Calısan>();
}
}
Here is a sample of a couple of ways to create the list a little more simply. Note the small change to the Calısan object to give it a default constructor and an overloaded constructor.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
////Calısan calisan = new Calısan() { ID = 1, Ad = "xxx", SoyAd = "yyy" };
MyCalısan myCalısan = new MyCalısan();
//option 1:
//==========
myCalısan.list.AddRange(new[] { new Calısan() { ID = 1, Ad = "xxx", SoyAd = "yyyy" }, new Calısan() { ID = 2, Ad = "blah", SoyAd = "jiggy" } });
//option 2:
//=========
myCalısan.list.AddRange(new[] { new Calısan(1, "xxx", "yyy"), new Calısan(2, "blah", "jiggy") });
////myCalısan.list.Add(calisan);
foreach (Calısan item in myCalısan.list)
{
Console.WriteLine(item.Ad.ToString());
}
Console.ReadKey();
}
}
public class Calısan
{
public Calısan() { }
public Calısan(int id, string ad, string soyad)
{
ID = id;
Ad = ad;
SoyAd = soyad;
}
public int ID { get; set; }
public string Ad { get; set; }
public string SoyAd { get; set; }
}
public class MyCalısan
{
public List<Calısan> list { get; set; }
public MyCalısan()
{
list = new List<Calısan>();
}
}
}