naver / fixture-monkey

Let Fixture Monkey generate test instances including edge cases automatically
https://naver.github.io/fixture-monkey
Apache License 2.0
575 stars 90 forks source link

Unable to generate correctly class annotated with @Data #781

Closed esfomeado closed 1 year ago

esfomeado commented 1 year ago

Describe the bug

If you have a class annotated with @Data and one field is final the class is not generated correctly.

I've tried a couple of things, either it's unable to generate the class or generates but the non final fields are set to null.

I can't really change the class where I'm facing this problem otherwise adding a all args constructor would solve this issue.

Your environment

Steps to reproduce

https://github.com/esfomeado/fixture-monkey-bug/blob/master/src/test/java/com/example/bug/FixtureMonkeyTest.java#L90C16-L90C16

Expected behaviour

Some fields are not populated

Actual behaviour

Should populate all fields

seongahjo commented 1 year ago

@esfomeado Hello, it is a tough question. I need more time to figure out a better way to handle this.

For a while it is better to use a special ArbitrayIntrospector just like below with pushExactTypeArbitraryIntrospector option.

public class MixedArbitraryIntrospector implements ArbitraryIntrospector {
        public static final MixedArbitraryIntrospector INSTANCE = new MixedArbitraryIntrospector();

        @Override
        public ArbitraryIntrospectorResult introspect(ArbitraryGeneratorContext context) {
            Map<ArbitraryProperty, CombinableArbitrary<?>> arbitraryListByArbitraryProperty =
                context.getCombinableArbitrariesByArbitraryProperty();

            return new ArbitraryIntrospectorResult(
                ConstructorPropertiesArbitraryIntrospector.INSTANCE.introspect(context)
                    .getValue()
                    .map(instance -> {
                        for (Entry<ArbitraryProperty, CombinableArbitrary<?>> arbitraryByArbitraryProperty : arbitraryListByArbitraryProperty.entrySet()) {
                            Property property = arbitraryByArbitraryProperty.getKey()
                                .getObjectProperty()
                                .getProperty();

                            if (property instanceof CompositeProperty) {
                                property = ((CompositeProperty)property).getPrimaryProperty();
                            }

                            if (property instanceof ConstructorProperty) {
                                continue;
                            }

                            try {
                                if (property instanceof FieldProperty) {
                                    ((FieldProperty)property).getField()
                                        .set(instance, arbitraryByArbitraryProperty.getValue().combined());
                                } else if (property instanceof PropertyDescriptorProperty) {
                                    ((PropertyDescriptorProperty)property).getPropertyDescriptor()
                                        .getWriteMethod()
                                        .invoke(instance, arbitraryByArbitraryProperty.getValue().combined());
                                }
                            } catch (Exception ex) {
                                // ignored
                            }
                        }
                        return instance;
                    })
            );
        }
    }

Thank you.

seongahjo commented 1 year ago

@esfomeado You can easily address it by new experimental feature in 0.6.12.

DataTest dataTest = fixtureMonkey.giveMeExperimentalBuilder(DataTest.class)
            .instantiate(
                Instantiator.constructor()
                    .field()
            )
            .sample();