-
Notifications
You must be signed in to change notification settings - Fork 179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Junit 5 extension for injecting Faker object at test methods #1405
Comments
@agomezlucena Why not just put this |
I like the idea in theory, it's actually a long time on my list to have better Junit 5 integration. However, at the same time, I'm not sure if Junit should be included in Datafaker, since we like to keep the core as free from dependencies as we can, and it probably wouldn't be ideal to tie it a specific test engine. Perhaps a module outside of the project would be more suitable at this moment? (datafaker-junit5 module or so, so that perhaps we can have a datafaker-testng or similar module in the future?) |
Couldn't you just create a class that extends Faker and has a constant or singleton you can re-use instead of numerous instantiations? |
I don't think there's any reason why you couldn't just create a class level instance of Datafaker, and reuse that over the tests. It's a one line thing, I wouldn't use a faker per test case, and I'm not a fan of using Faker directly in a test class either, I use object mothers in 99% of the time. But on the other hand, I also wouldn't mind having something like "DatafakerSource" similar to CsvSource etc for parametized tests. It can be done by creating a MethodSource, but I always have to look up the correct syntax. So I was hoping that maybe a junit5 project could be the start of some native integration, and we'll see where it takes us? |
@asolntsev mainly because with the extension we have a better experience of development, because is integrated with junit5 framework, and if the extension grow in complexity, complex things like csvmodel can be also added.
@bodiam I'm currently have a prototype, but I think is not good enough, because do just the parameter injection. Whatever if you want I can create the PR. |
Sorry, but I don't understand this explanation. I still don't see any benefits in such extension. If I understand your answer correctly, you want an extension that would be your project-specific, and its complexity would grow with your project. If so, the extension should be located in your project, not in datafaker. |
You can make a PR, so we have something to discuss more indepth, but at this stage, it will probably unlikely that Junit will be a dependency of Datafaker. We have a section on that in the contributing guide here: https://github.com/datafaker-net/datafaker/blob/main/CONTRIBUTING.md#dependencies However, if the PR is a good basis for further development, a special datafaker-junit layer could be good. For Mocktio and Junit, things might be different. While Datafaker is mainly a library used in testing, some people use it also for production usage (I do that myself on a few projects). It wouldn't be beneficial to me to get a transitive dependency on JUnit in my production code just by introducing Datafaker, so that's something I'd like to avoid. |
@bodiam This is the branch that have the changes: https://github.com/agomezlucena/datafaker/tree/create-junit-extension. |
Yes I can make it, but i will need to copy that class in every project / module or create a test fixture for that, and in general this can be standarized and automatized with a extension to junit. And also this can evolve into inject directly providers or values using annotations (I currently have this kind of functionality in a personal project) and made the code much more cleaner, because you dont need to initialize the data just use an annotation like
|
The PR is a bit overwhelming indeed with the rename. Wouldn't it be less change to create the project as a completely separate project, and have a dependency of Datafaker instead? We could publish it, or you foto's publish it under a different name, even something like io.github.datafakerjunit would do, as a sort of incubator? If we notice that there's a reasonable demand for it, we could consider integrating it into the core. Would that be something which could work? Cause I like the idea, and I like that you built it! |
Sure I can make it, the main issue that I have in mind is the publication, because if I publish the dependency by myself, nobody |
@agomezlucena I don't mind that. If you're okay with it, we can make another repo here, and publish it under the Would that work? @kingthorin , @asolntsev what do you think? Want to give this a try? |
Sounds good to me. We already have repos for other related things. |
I have a feeling that nobody listens to me. :( We don't need this extension. It doesn't bring any additional value. It's just the same as holding Faker instance in a static variable. KISS. Avoid unneeded comexity. YAGNI. Amen. |
@asolntsev my thinking here was that @agomezlucena put in the effort of creating this extension, so most likely it serves a need. I rather be convinced by code then by opinions. Perhaps this could be a starting point for adding the things I already described above. However, maybe it's too early to put this in the Datafaker repo. So, @agomezlucena I think it would be better to put this in your own repo for now, and I'm happy to put a link in the documentation to your extension. If people start using it, there's probably a bigger need, and we'll integrate it into the Datafaker organisation if you still want that. |
Sorry, but this is a very false assumption. :)
P.S. Though, I personally don't see any value in this annotation as well. This is equvalient to the old good |
Perhaps, and some people criticize, and some people create.
That's your right. Other people do. I don't really see the point of this discussion to be honest, if someone wants to build something, let them, and if you don't see the value in it, that's fine, but that shouldn't stop anyone. The whole point of this project is that contributions are welcome, and not that they are shot down before they've landed, so a bit more welcoming to ideas which don't per se align with yours would be appreciated. PS: I personally still see a lot of value in the Annotation approach. I'm not a big fan of the Schemas, I find them too complex, and something like:
would be much more expressive and clear to me. And if you don't like it, I can live with that, I'll build it anyway one day, since it serves a need for me. |
May be I'm late here it requires some time to get familiar with it. At the same time the main downside of all those fancy annotations like
is that
with embedded java object population feature it could satisfy all of them however it is not that user friendly |
I was hoping we could generate them perhaps, based on the names of our current classes. I haven't done a POC yet, but that's what I had in mind. I wouldn't think it would be great to maintain them by hand. |
yes, they can be generated and released for those which are in datafaker's repo We can create some instructions or even tools however it will not be fully automated |
I can live with that. Perhaps there could be a different annotation or something for that ( |
up to you however as I mentioned there is already existing functionality |
I'm not a fan of schemas. I find the syntax too complex, and I always have to look up how that works. As a result, I never use it. I think an annotation based approach would be simpler. Why would the number of fields be an issue regarding annotations? |
at least one annotation per field -> 2 times more code usually after 5 fields it becomes noticeable |
What becomes noticable? Sorry, I don't understand what the issue is here. I'm talking about an approach like:
Pretty common if you use JSON/Hibernate. Am I missing something here? You also said:
That would be the same for creating a Schema mapping, it's just moving the code from annotations to a schema. |
Let's consider more concrete case class Person {
private String firstName;
private String lastName;
private LocalDate dateOfBirth;
private List<String> phoneNumbers; // e.g. several phone numbers
} As you mentioned it could be that
going further:
yes however
|
Yes. And it's pretty common to call it "Annotation hell". :) |
for me the idea behind is to inject data in test method, if we need to create more complex data we just can simply create an annotation with a parameter @ExtendWith(DatafakerJupiterExtension.class)
class PersonTest {
@Test
void shouldAllowToChangeTheName(
@CustomProvider(generator=PersonGenerator.class) Person givenPerson,
) {
var expectedName= "Jotaro";
var previousName= givenPerson.getName();
givenPerson.setName(expectedName);
var obtainedName = givenPerson.getName();
assertNotEquals(previousName, obtainedName);
assertEquals(expectedName, obtainedName);
}
} This is framework code @Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomProvider {
Class<? extend CustomObjectGenerator> generator();
} public abstract class CustomObjectGenerator<T> {
protected Faker getFakerInstance(){
return FakerSharedInstance.getInstance();
}
public abstract T newObject();
} This is user code public class PersonGenerator extends CustomObjectGenerator<Person> {
@Override
public Person newObject(){
var faker= getFakerInstace();
return Person.builder()
.name(faker.name().firstName())
.lastName(faker.name().lastName())
.phoneNumber(faker.phoneNumber().cellPhoneInternational())
.build();
}
} |
I still didn't get it... the second bullet
Faker internally has knowledge about locale and seed which it should use to generate data how user can generate Japanese name if default locale (when faker create without arg is |
we can parameterize the locale if is required, and if present we set the locale to the parameterized one and if not we set it to english or system default. |
going back to the example class Person {
private String firstName;
private String lastName;
private LocalDate dateOfBirth;
private List<String> phoneNumbers; // e.g. several phone numbers
} can you please show how it should be annotated with new annotations (let's say potentially added in future) to satisfy the case above?
Just using existing functionality (present since beginning of 2023) var faker = new Faker(Locale.forLanguageTag("ja-JP"));
var jpSchema = Schema.of(
field("firstName", () -> faker.name().firstName()),
field("lastName", () -> faker.name().lastName()),
field("dateOfBirth", () -> new LocalDate()), // feel free to replace with what you prefer
field("phoneNumbers", () -> faker.collection(() -> faker.phoneNumber().cellPhoneInternational()).len(2).generate());
); and then just use it to generate objects Person person = BaseFaker.populate(Person.class, jpSchema); need objects built in a bit different way? Person person = BaseFaker.populate(Person.class, otherSchema); so I don't understand why we need another one custom object generator |
No. I consider Datafaker most a test library, why would you enrich your Hibernate objects with Datafaker objects? That sounds like not a great idea.
Using Junit support in Datafaker vs annotations for schemas is a whole different conversation, it might be best to keep those discussions separate.
That's okay. I'm not asking you to build it. I'll build it. |
This code might look okay-ish in Java, but try to make this work in Kotlin, and you might see why I'm not a fan of the current schema approach. |
Hi I used for some months this project and I saw that sometimes we need to have some boilerplate code for use it.
Right now we must to create always an instace and setup manually the injection of the Faker object in our test cases like this
or
But this could be repetitive and make that the logic of the test a litte bit messy.
The Idea is to create a Junit5 extension that allows you to inject a shared faker instance in the test with something like this:
I think that this kind of extension would improve the legibility of the tests and the usability of the library.
The text was updated successfully, but these errors were encountered: