Giter Site home page Giter Site logo

progala2 / buildenator Goto Github PK

View Code? Open in Web Editor NEW
19.0 3.0 1.0 200 KB

A test data builders source generator for .net 5 and later.

License: MIT License

C# 100.00%
sourcegenerator csharp dotnet dotnet-standard dotnetcore builder builders analyzer

buildenator's Introduction

Buildenator

A test data builders source generator for .net 5 and later.

A simple usage example

The following code:

using Buildenator.Abstraction;
using Buildenator.Abstraction.AutoFixture;
using SampleProject;

namespace SampleTestProject.Builders
{
    [MakeBuilder(typeof(DomainEntity))]
    [AutoFixtureConfiguration()]
    public partial class DomainEntityBuilder
    {
    }
}

Will generate something very close to this source code:

using System;
using System.Linq;
using Buildenator.Abstraction.Helpers;
using SampleProject;
using AutoFixture;


namespace SampleTestProject.Builders
{
    public partial class DomainEntityBuilder
    {
        private readonly Fixture _fixture = new Fixture();

        public DomainEntityBuilder()
        {

        }

        private Nullbox<int>? _propertyIntGetter;
        private Nullbox<string>? _propertyStringGetter;


        public DomainEntityBuilder WithPropertyIntGetter(int value)
        {
            _propertyIntGetter = new Nullbox<int>(value);
            return this;
        }


        public DomainEntityBuilder WithPropertyStringGetter(string value)
        {
            _propertyStringGetter = new Nullbox<string>(value);
            return this;
        }

        public DomainEntity Build()
        {
            return new DomainEntity((_propertyIntGetter.HasValue ? _propertyIntGetter.Value : new Nullbox<int>(_fixture.Create<int>())).Object, (_propertyStringGetter.HasValue ? _propertyStringGetter.Value : new Nullbox<string>(_fixture.Create<string>())).Object)
            {

            };
        }

        public static DomainEntityBuilder DomainEntity => new DomainEntityBuilder();

        public System.Collections.Generic.IEnumerable<DomainEntity> BuildMany(int count = 3)
        {
            return Enumerable.Range(0, count).Select(_ => Build());
        }

        public static DomainEntity BuildDefault(int _propertyIntGetter = default(int), string _propertyStringGetter = default(string))
        {
            return new DomainEntity(_propertyIntGetter, _propertyStringGetter)
            {

            };
        }

    }
}

Check Buildenator.IntegrationTests for more examples.

Feel free to contribute!

buildenator's People

Contributors

progala2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

gtechsltn

buildenator's Issues

Sophisticated domain subentities creation methods

The golden sample

the source generator should have possibility to generate as follows:
Source:

public class Aggregate
{
     public Entity Entity  { get; set; }
     public IEnumerable<Entity> Entities  { get; set; }
}

public class Entity
{
    /*    */
}

[MakeBuilder(typeof(Aggregate), <NewOption?>)]
[<NewAttribute?>]
public partial class AggregateBuilder
{
}

Output:

public partial class AggregateBuilder
{
     private Entity _entity;
     public AggregateBuilder WithEntity(Func<EntityBuilder, EntityBuilder> configureEntity)
     {
            _entity = configureEntity(new EntityBuilder());
            return this;
     }
     private IEnumerable<Entity> _entities;
     public AggregateBuilder WithEntities(params Func<EntityBuilder, EntityBuilder>[] configureEntities)
     {
            _entities = configureEntities.Select(x => x(new EntityBuilder()));
            return this;
     }
}

Detecting entities to generate methods

Namespace rule

To prevent generating wrongly builders for build-in types, or types from external libraries, the buildenator will detect subentities by the same root namespace of the parent entity.

e.x.
this is correct:

NameSpaceRoot.Aggregate
NameSpaceRoot.SubNamespace.Entity

this is not correct:

NameSpaceRoot.Aggregate
SubNamespace.Entity

Filtering out value types

By default if the subentity has only one not sophisticated property/contr. parameter, it will be treated as a value type, so default methods will be created.

Configurability

  • UseSubentityBuilders[True/False]: whether using subentity builders [False by default]
    • Should have possibility to set up a global config

Add a partial method to generated builder class for post build steps

It would be great if the generated builder class included something like the following:

partial void PostBuild(<<type>> buildResult);

the developer could then implement this method to do additional work to the result before it is returned. The Build method would need to call this before it returns a result.

Ability to include name of property for autofixture generation

I'm trying to integrate Buildenator + AutoBogus into a project, and I've hit an issue.

Currently when generating the properties I can only see the type of the property by overriding the additionalConfiguration string and using {0} for the type.

It would be useful if the name of the property was also included in this template (with {1} for example) so as to provide extra customisation depending on the property name.

Thanks

Generated files should be marked as auto-generated to avoid Code Analysis errors

I just added a builder to my test project and ended up with hundreds of code analysis errors.

The generated code should include a header to say that it's generated. Here's an example:

// ------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a source generator named Vogen (https://github.com/SteveDunn/Vogen)
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------

Remove default constructor from builder

It would be great to remove the default constructor from the generated builder so that the partial class can define one of its own so that it could initialize any of the fields that are generated.

Generating subentites builders

The golden sample

the source generator should have possibility to generate as follows:
Source:

public class Aggregate
{
     public Entity Entity  { get; set; }
}

public class Entity
{
    /*    */
}


[MakeBuilder(typeof(Aggregate), <NewOption?>)]
[<NewAttribute?>]
public partial class AggregateBuilder
{
}

Output:

public partial class AggregateBuilder
{
     /*    */
}

public partial class EntityBuilder
{
    /*   */
}

Detecting entities to generate builders

Namespace rule

To prevent generating wrongly builders for build-in types, or types from external libraries, the buildenator will detect subentities by the same root namespace of the parent entity.

e.x.
this is correct:

NameSpaceRoot.Aggregate
NameSpaceRoot.SubNamespace.Entity

this is not correct:

NameSpaceRoot.Aggregate
SubNamespace.Entity

Filtering out value types

By default if the subentity has only one not sophisticated property/contr. parameter, it will be treated as a value type, so no additional builders will be created.

Configurability

  • GenereteSubentitiesBuilders[True/False]: whether generating subentities builders [False by default]
    • Should have possibility to set up a global config

Known problems and challenges

  • How to easilly detect whether the entity is simple or not?
  • Secondly, what about reference loop, i.e. one entity having the second one and vice versa?
    • It should be one directional, and it means it'd require to remember what are parent entities and pass them to children.
  • A user should have a possibility to override the subentities builder in a partial class. Probably it'd require an additional marker

For the future

  • A thing to improve in the next iterations - loosen namespace rules, i.e. detect by the number of identifiers taken into the account.
    For example, if the AR has its namespace A.B.C.D, and we set up the number of identifiers to 2, then the generator will generate builders for each entity that has its namespace in the A.B scope.

Ability to set not accessible properties by the reflection

As the title says.
Sometimes some properties are set only by some methods of the object. For some scenarios it would be useful to set it manually instead of calling some logic around.

Acceptance Criteria:

  • Disabled by default
  • Two modes if the "with" method is not used
    • Default: do nothing on creation
    • generate some value from the given fixture

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.