tynamix / objectfiller.net Goto Github PK
View Code? Open in Web Editor NEWThe .NET ObjectFiller fills the properties of your .NET objects with random data
Home Page: http://objectfiller.net
License: MIT License
The .NET ObjectFiller fills the properties of your .NET objects with random data
Home Page: http://objectfiller.net
License: MIT License
Randomizer.Create
has currently three overloads. One so we can use plugins, one to define a Setup and one to create a collection of elements.
This is a bit unhandy because it means that we are not able to create collections with specific setups or plugins. That's why we need two additional overloads. one for collections and plugins, as well as one for collections and setups.
I guess it's not usefull to have an overload with setup and plugin.
Hi
Thanks for your awesome library.
I want to use you library but I need some overload. You method is pure generic but I think it is better to have Type based and PropertyInfo based overload. for example
.OnType(typeof(Person)).Use()
OnProperty(PropertyInfo of FirstName).Use()
and ...
because some one like me use your library for set objects in Runtime and need Type instead of Generice model
please create Type overloads for all generic methods too.
Current we need to do something like this to create a setup:
var categoryFiller = new Filler<Category>();
var categorySetup = categoryFiller.Setup().OnType<int>().Use(new IntRange(1, 100)).Result;
It would be nice to skip the Filler and create a setup like this:
var categorySetup = Setup<Category>.OnType<int>().Use(new IntRange(1, 100)).Result;
When I am testing with entity classes generated by Entity Framework, it would be nice to ignore all complex types because these complex types are often references to other data tables and the actual data is mostly stored as numbers or strings.
We could check if a type is a reference type and not string and ignore it than.
I saw that we are using optional parameters in our public API. For example in Lipsum:
public Lipsum(LipsumFlavor flavor, int paragraphs = 3, int minSentences = 3, int maxSentences = 8, 160 int minWords = 10, int maxWords = 50, int? seed = null)
Optional parameters are compiled into the Client library. This might cause Problems if we change them, which why they shouldn't be used in public APIs. On the other hand it's annoying to replace them with overloads.
My question is now: Do we want to replace all optional parameters with overloads to stay save or do we want to keep them as they are, even with possible side effects?
I'm using your handy ObjectFiller for unit testing legacy code. This legacy code includes a lot of classes that inherit from List. Some of these list types include additional properties to fill. Please consider adding more support for such types.
public class EntityA
{
public string Name { get; set; }
public int ID { get; set; }
public EntityBList Bs { get; set; }
}
public class EntityB
{
public string Name { get; set; }
public Guid ID { get; set; }
}
public class EntityBList : List<EntityB>
{
public DateTime SomeDate { get; set; }
}
My ultimate goal is to call new Filler<EntityA>().Create()
and get back an EntityA object whose Bs property has both SomeDate filled and also has some EntityB items whose properties are filled. As is, I end up manually coding the EntityBList handling using something like this:
Setup().OnProperty(x => x.Bs).Use(delegate () { EntityBList ebl = new EntityBList(); ebl.SomeDate = DateTime.Now; Filler<EntityB> fb = new Filler<EntityB>(); ebl.AddRange(fb.Create(4)); return ebl; });
Since we have a great many of these types, that ends up being a lot of code.
I think this would require several enhancements.
First, Filler doesn't seem to recognize EntityBList as an IList to be filled. Filler sees that this inherits IList. Filler then checks whether the type has generic arguments, but this one does not. It's base class has the generic arguments.
Second, given that it doesn't treat this type as a list, Filler attempts to set the Capacity and Item properties. Those throw exceptions. I can set it up to ignore the Capacity property by using Setup().SetupFor<EntityBList>().OnProperty(x => x.Capacity).IgnoreIt()
but have not figured out a way to ignore the special Item property which represents the this[int] indexer.
Third, I suspect that Filler either treats the type as a list to be filled or treats it as an object whose properties should be filled, and not both. I'd want it to fill the list and also fill the properties.
We do also have a couple types that inherit from Dictionary<>. It'd be nice to cover those in the same way.
Given the following class:
public class Order
{
public IReadOnlyCollection<string> OrderLines { get; set; }
}
Filling it by running the following code fails.
var filler = new Filler<Order>();
var order = filler.Create();
The following exception is thrown:
System.InvalidOperationException: This operation is only valid on generic types.
at System.RuntimeType.GetGenericTypeDefinition()
at Tynamix.ObjectFiller.Filler`1.<>c.<TypeIsCollection>b__13_0(Type x)
at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
at Tynamix.ObjectFiller.Filler`1.TypeIsCollection(Type type)
at Tynamix.ObjectFiller.Filler`1.CreateAndFillObject(Type type, FillerSetupItem currentSetupItem, HashStack`1 typeTracker)
at Tynamix.ObjectFiller.Filler`1.FillInternal(Object objectToFill, HashStack`1 typeTracker)
at Tynamix.ObjectFiller.Filler`1.Create()
Using an ICollection<string>
instead works.
An InvalidOperationException is thrown if a class has a nullable enumeration:
public class MyClass { public MyEnum? TheEnum {get; set; } }
public enum MyEnum { A, B, C }
Randomizer.Create(); <-- Exception
Same happens with the filler class.
var filler = new Filler<Office>();
IEnumerable<Office> offices = filler.Create(1);
CollectionAssert.AreEquivalent(offices, offices);
Will fail because the compared collection does not contain the same instances. I guess the reason is, that Create uses yield which creates new instances when ever the enumerator if IEnumerable is used. E.g. in case of foreach.
Would it be possible for to create a filler and merge the setup with another filler allowing the class to configure a filler aginst one interface and merge it where that interface inherits the other. This same method could also be used where a class inherits another.
For example:
public interface ITrackable { DateTime Timestamp {get;set;} }
public interface IPerson: ITrackable { string Name {get;set;} }
var person = FillerSetup.Create<IPerson()...
var trackable FillerSetup.Create<ITrackable>()...
person.Merge(trackable)
It would be good if there is a possibility to get the current setup which was made with the fluentAPI from the objectfiller to reuse it.
I wanted to create a list of objects. They must be of type object. I was not able to create them with Randomizer.Create(110) because there was no type Object registered.
Exception:
System.TypeInitializationException : Der Typeninitialisierer für "System.Object" hat eine Ausnahme verursacht.
----> System.Exception : The type [Object] was not registered in the randomizer.
bei Tynamix.ObjectFiller.Filler1.GetRandomValue(Type propertyType, FillerSetupItem setupItem) bei Tynamix.ObjectFiller.Filler
1.CreateAndFillObject(Type type, FillerSetupItem currentSetupItem, HashStack1 typeTracker) bei Tynamix.ObjectFiller.Filler
1.Create()
bei Tynamix.ObjectFiller.Filler`1.Create(Int32 count)
Then I tried this setup:
Filler<object> objectFiller = new Filler<object>();
objectFiller.Setup().OnType<object>().CreateInstanceOf<string>();
with this call:
objectFiller.Create(110)
and got the same Exception.
Comes from #63
For complex scenarios it is good to have plugins which decide by their own if they can be used for a specific type or not.
This is not possible with IRandomizerPlugin because of its concrete typing. That's why it would be nice to have a IRandomizePlugin without typing but with an additional method to check if it can be used.
For example I have following class:
public class Address
{
public string Street { get; set; }
...
}
Currently it Is not possible to call:
Randomizer<Address>.Create(new Mnemonic());
because Mnemonic is of type IRandomizerPlugin and not IRandomizerPlugin
.The dynamic version of the plugin must then be referenced for each type and property within our resolution routine.
The signature of the plugin could look like:
public interface IRandomizerPlugin
{
bool CanBeUsedOn(Type type);
object GetData();
}
The basic advantage is, that one plugin can be used for multiple types.
There is no default randomizer for type URI. Here is one prepared and can be included to objectfiller.
public class RandomUri : IRandomizerPlugin<Uri>
{
/// <summary>
/// Gets random data for type <see cref="Uri" />
/// </summary>
/// <returns>Random data for type <see cref="Uri" /></returns>
public Uri GetValue()
{
var http = Randomizer<bool>.Create() ? "http" : "https";
var www = Randomizer<bool>.Create() ? "www." : string.Empty;
var host = Randomizer<string>.Create(new MnemonicString(1)).ToLower();
var domain = Randomizer<string>.Create(new RandomListItem<string>("de", "com", "org", "uk", "gov", "fr", "ru"));
string relativePath = string.Empty;
if (Randomizer<bool>.Create())
{
var relativeElements =Randomizer<int>.Create(new IntRange(1, 4));
for (int i = 0; i < relativeElements; i++)
{
relativePath += $"/{Randomizer<string>.Create(new MnemonicString(1)).ToLower()}";
}
}
UriBuilder u = new UriBuilder(http, $"{www}{host}.{domain}{relativePath}");
return u.Uri;
}
}
When I generate a string then I get usually something like this by default: "Tabedojimij Vedezosodul magoserotom gowatafumim Dibopaselim sorokesosoj Kirugisebob vorowavucob Jatalefihup gunirapejol Jibucelonez Jabebuwujuw Kajafijacuk wahikokakef Bicakujakiw Lenutekovaf sojabecojas banegikumet ziwagemihuj Vazatotudon"
That's not wrong but I usualy only need a short phrase like "Tabedojimij". I would suggest that we change the default behaviour of the filler so it creates only one word when no setup for strings is given.
Thanks to Entity Framewok, I am currently in a situation where I need to ignore more properties than I actually need for a test. It would be nice to have a method where I can say, that the Filler should ignore every thing which is not configured explicitly.
Hi,
I have an object with a property of type 'HashSet'.
When I try to fill it, the following exception occurs:
Unable to cast object of type 'System.Collections.Generic.HashSet`1[System.String]' to type 'System.Collections.IList'.
In the source code a check is made against 'IEnumerable', and if true, a cast to 'IList' is made, which causes an exception.
Hello. I ran into an issue when trying to fill in a System.Drawing.Color value using object filler.
Here's the error message that happens when running the test:
System.Exception : The type [Color] was not registered in the randomizer.
Here's the stacktrace:
Result StackTrace:
at Tynamix.ObjectFiller.Filler`1.GetRandomValue(Type propertyType, FillerSetupItem setupItem)
at Tynamix.ObjectFiller.Filler`1.CreateAndFillObject(Type type, FillerSetupItem currentSetupItem, HashStack`1 typeTracker)
at Tynamix.ObjectFiller.Filler`1.FillInternal(Object objectToFill, HashStack`1 typeTracker)
at Tynamix.ObjectFiller.Filler`1.Create()
To attempt to solve this issue, I followed the documentation listed on how to make a plugin, and my code is as follows:
public class argbColorPlugin : IRandomizerPlugin<Color>
{
private readonly Random r = new Random();
private readonly List<Color> allColors =
new List<Color>()
{
System.Drawing.Color.Beige,
System.Drawing.Color.FromArgb(new IntRange(0, 255).GetValue(), new IntRange(0, 255).GetValue(), new IntRange(0, 255).GetValue(), new IntRange(0, 255).GetValue())
};
public Color GetValue()
{
return allColors[r.Next(0, allColors.Count)];
}
}
Even after calling the plugin instead of passing in a Color, it still has the same error.
Here's how I'm calling it:
.OnProperty(x => x.FontColor).Use(new argbColorPlugin().GetValue())
It's in the middle of a bunch of other properties, mostly floats, but a couple other object types are present. All of the rest of them seem to work pretty well.
Is there something that I'm supposed to do in order to register the type in the randomizer?
Thanks!
public class User
{
public int Id { get; set; }
public Person Person { get; set; }
public List<string> Phones { get; set; }
}
public class Person
{
public Guid Id { get; set; }
public int No { get; set; }
public string NationalCode { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
}
Filler<Person> pFiller = new Filler<Person>();
var fillerSetup = pFiller.Setup()
.OnType<string>().Use("PERSON");
Filler<User> uFiller = new Filler<User>();
pFiller.Setup(fillerSetup.Result)
.OnType<string>().Use("USER");
User p = uFiller.Create();
above example does not work I can not merge Persons filler with User
s filler. (I dont want to use SetupFor<>)
Can you provide this feature ? of course unlimited Setup() for multiple merge
I have following code which will fail on Create:
var filler = new Filler<Address>();
filler.Setup().OnProperty(x => x.Id).Use("1");
this.address = filler.Create();
Id is a string in which numerals are stored like 1, 2 or 3. It seems that the filler tries to convert the number into an integer and is then unable to assign this number to the actual string.
I would like to see the ability to use an interface when creating an instance of a filler for example something like:
Filler<ISomething> somethingFiller = new Filler<ISomething>(()=>{ return new Something() }).Setup()...
Null reference exception!
TODO:
I have following classes without any inheritance:
public class Position
{
public int Company;
public int LeaseNumber;
public decimal Costs;
}
public class SubPostion
{
public int LeaseNumber;
public int InventoryNumber;
public string Status;
}
These will be joined in the database based on the LeaseNumber. Therefor I would like to create SubPositions based on the data of positions by using the Position object as some kind of template object so that properties that have the same name in both classes will get the same data.
var position = Randomizer<Position>.Create();
var setup = FillerSetup.Create<SubPosition>().UseTemplate(position).Result;
var subPositions = Randomizer<SubPosition>.Create(setup, 10);
In the case above, all subPositions have random data for InventoryNumber and Status but the same LeaseNumber as the Position object.
It is important, that the template object does not need to be of the same type as the objects are I want to create. Thus we need to check for each property if the template has a property with the same name.
if I have class like this:
class TestClass
{
public int? MyNullableInt { get; set; }
public bool MyBool { get; set; }
}
everything seems fine, and filler creates new instance
new Filler<TestClass>().Create(); //everything OK! :)
but if I change bool
to bool?
class TestClass
{
public int? MyNullableInt { get; set; }
public bool? MyNullableBool { get; set; }
}
Filler crashes
new Filler<TestClass>().Create(); //System.Exception was thrown (with message, The type [Nullable`1] was not registered in the randomizer.)
Of course, I can work around this, by writing
var filler = new Filler<TestClass>();
filler.Setup().OnType<bool?>().Use(new bool[] { true, false });
var testClass = filler.Create();
but I believe that to do so should not be necessary
In Bug #63 there was mentioned that the type ArrayList
can not be generated. I will write a plugin for that.
For now, objectfiller is not able to handle arrays. It have to be implemented
Create:
Update:
Using the following code, allmost all instances of Foo have the same description text (sometime there are two versions of text in those 1000 instances):
var foos = new Filler<Foo>();
filler.Setup()
.OnProperty(foo => foo.Description)
.Use(new Lipsum(LipsumFlavor.LoremIpsum))
.Create(1000);
Be default I would have expected that they all have a different text.
The reason why this happens is probably because the Lipsum
randomizer creates a new Random
instance at the beginning of each GetValue()
call (with the same seed, because in most cases Environment.TickCount
has the same value for all 1000 calls).
Instead it should create the Random
instance in the Lipsum
constructor store it in a field and use that same istance for each random.Next()
call inside GetValue()
I can work around this issue by doing:
var seed = 0;
var filler = new Filler<Todo>();
filler.Setup()
.OnProperty(t => t.Description)
.Use(() =>new Lipsum(LipsumFlavor.ChildHarold, seed++).GetValue()))
.Create(1000);
It could be a lot easier! Have to reimplement the random list item plugin!
It would be nice if I could assign plugins to collections of corresponding values. I have following setup:
var filterFiller = new Filler<FilterVM>();
filterFiller.Setup()
.OnProperty(x => x.Countries).Use(new CountryName());
CountryName can not be assigned to Countries because Countries is a collection of strings and the plugin implements IRandomizerPlugin. It would need to implement IRandomizerPlugin<IEnumerbale> to work.
I guess it would be best if the filler could automatically use a IRandomizerPlugin on collections no matter if it is written for collections or not otherwise we have to implement two Interfaces with each plugin.
When using objectfiller with tests, it might be necessary to use allways the same data. A full fledged filler setup is to much in this case, because we would like to generate data to keep the amount of code low, but this data should be generated allways the same way to make sure that the tests run the same ways each and every time.
I wanted to use your library in my Unittests but it doesn't start.
ObjectFiller was added with nuget to my Project, which is a project with a strong name.
System.IO.FileLoadException : Could not load file or assembly 'Tynamix.ObjectFiller, Version=1.5.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. A strongly-named assembly is required. (Exception from HRESULT: 0x80131044)
Would it be possible to publish ObjectFiller with a strong name on nuget?
Today I built a search form where I added additional Information for the the UI by inheriting the view model from the actual model:
public class Filter
{
public string Name { get; set; }
}
public class FilterViewModel : Filter
{
public string[] AvailableNames {get; set; }
}
In this case it would be nice to have an option so the filler generates only data for the ViewModel.
It could be handled the same way as "IgnoreUnknownTypes".
var filterFiller = new Filler<FilterViewModel >();
filterFiller.Setup().IgnoreInheritance();
It would be good to just use a plugin without additional settings.
For example if you want to use the MnemonicString plugin you have to setup at least the word count.
We should change this, that every plugin would also work with a parameterless constructor.
Another advantage is, that we can use the IRandomizer plugins as constructable type parameters.
It does not create a instance :(!
That would be great ... :)
I have following classes:
public class A
{
public string Test { get; set; }
}
public class B
{
public A MyA {get; set; }
}
public class C : B
{
public string AnotherProperty {get;set;}
}
I have configured the filler as followed:
var filler = new Filler<C>();
filler.Setup().IgnoreInheritance();
var c = filler.Create();
I woul expect that Cs property "MyA" is null but its actually an empty A.
Hi,
getting a stack overflow with a reasonably simple setup (for a class with an ICollection defined on it and some properties I don't set up at all, one being of another type); sorry I don't have more time right now but I will investigate and maybe throw a pull request your way if I figure something out.
Just from a cursory look at the code though, would I be right in saying that the SetupManager being static and the Filler calling Clear in the constructor will effectively prevent me from creating several fillers and playing around with them?
Either way, I like the style of the library so maybe I'll contribute with some actual code one of these days :)
I would like to use setups again for child types like shown in following test. I've allready tried to implement it but was not able to in short of type because the Use method of the parent does not seem to have information about the child type.
public class Parent
{
public Child Child { get; set; }
}
public class Child
{
public int Value { get; set; }
}
[TestMethod]
public void UseSetupsAgainForPropertyConfigurations()
{
int givenValue = Randomizer<int>.Create();
var childFiller = new Filler<Child>();
var childSetup = childFiller.Setup().OnProperty(x => x.Value).Use(givenValue).Result;
var parentFiller = new Filler<Parent>();
parentFiller.Setup().OnProperty(x => x.Child).Use(childSetup);
var parent = parentFiller.Create();
Assert.AreEqual(givenValue, parent.Child.Value);
}
There's currently a bug with the implementation of thread safe random access that was committed. It uses a static constructor to initialize a ThreadStatic marked field, which will cause subsequent threads to throw a null reference exception. Initialization at the field level or static constructor level for a ThreadStatic field will only ever run once on the first thread to reach the type, any subsequent threads will access an uninitialized variable.
This is an important feature to my company's usage of the library and we were hoping to avoid maintaining a fork just for this change, so I'm submitting a pull request to add a new unit test and correct the bug. More details in the PR (#61)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.