bchavez / bchavez/Bogus

Alllow Generate JsonNode/Proxy of Faker<T>

Open
#458 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
9.7k
Forks
538
PR merge metrics
No merged PRs in 30d

Description

The typed Faker class is great to create complex builder scenarios, the power of defining the shape of the type in parts as necessary is one of the best things to solve problems like test scenarios.

Something like this:
```cs
public class User
{
public string Name { get; init; }
public int Age { get; init; }
public string Email { get; init; }
}

var builder = new Faker()
.RuleFor(x => x.Email, f => f.Person.Email)
.RuleFor(x => x.Age, f => f.Random.Int(18, 50))
.RuleFor(x => x.Name, f => f.Person.FirstName);
```

Things get a bit complicated when the Type has a complex constructor or a mix with required properties:

```cs
var builder = new Faker()
.RuleFor(x => x.Age, f => f.Random.Int(18, 50))
.RuleFor(x => x.Name, f => f.Person.FirstName)
.CustomInstantiator(f =>
new User(f.Person.Email)
{
Name = // need to be set //,
Age = // need to be set //,
});
```
In this case, we kinda lost the power of member composability. If it was a custom builder I would have to create fields to hold values for the `CustomInstantiator` etc.

So would be nice to have a way to get the shape of the data without constructing the actual Type

A generic way to solve this could be to have a new method like `GetJsonObject`, which for the case above could be something like:

```cs
var builder = new Faker()
.RuleFor(x => x.Email, f => f.Person.Email)
.RuleFor(x => x.Age, f => f.Random.Int(18, 50))
.RuleFor(x => x.Name, f => f.Person.FirstName);

var values = builde.GenerateJsonNode();
/*
new JsonObject
{
["Name"] = "Casey",
["Age"] = 22,
["Email"] = "Casey_Ebert22@hotmail.com",
};
*/

```

So it could be used on the complex constructor, preserving the member composability:

```cs
var builder = new Faker()
.RuleFor(x => x.Email, f => f.Person.Email)
.RuleFor(x => x.Age, f => f.Random.Int(18, 50))
.RuleFor(x => x.Name, f => f.Person.FirstName)
.CustomInstantiator(f => {
var values = f.GetJsonObject();
return new User((values["Email"].GetValue())
{
Name = values["Name"].GetValue(),
Age = values["Age"].GetValue(),
});
}
```

Another solution would be use [Castle](https://github.com/castleproject/Core) `DynamicProxy` to maintain the type contract but `mocking` the property values:

```cs
var builder = new Faker()
.RuleFor(x => x.Email, f => f.Person.Email)
.RuleFor(x => x.Age, f => f.Random.Int(18, 50))
.RuleFor(x => x.Name, f => f.Person.FirstName)
.CustomInstantiator(f => {
var proxy= f.GetObjectProxy();
return new User(proxy.Email)
{
Name = proxy.Name,
Age = proxy.Age
});
}
```

* Is the feature something that currently cannot be done?
I don't think so

* What alternatives have you considered?
Customize the Faker inheriting from it, or just create/initialize all the properties manually

* Is this feature request any issues or current problems? No

* Has the feature been requested in the past? No

**If the feature request is approved, would you be willing to submit a PR?**
*Yes*

Contributor guide

Open the contributing guide

Research direction

The issue centers on Faker and CustomInstantiator; first review how those entry points currently compose member rules and construct values. Compare the proposed GenerateJsonNode and Castle DynamicProxy directions, then define the supported API and tests needed to show composed values are available without constructing User.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
testing-qa
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.