Is there a Java alternative to Ploeh's AutoFixture for .Net?
-
19-06-2021 - |
문제
I am looking for a Java tool that would create anonymous variables (variables whose value I don't care about) in my tests, similar to AutoFixture in .Net. Here is a link to AutoFixture's readme, which has pretty good examples of what it does.
Here is a short example taken from the same readme:
[TestMethod]
public void IntroductoryTest()
{
// Fixture setup
Fixture fixture = new Fixture();
int expectedNumber = fixture.CreateAnonymous<int>();
MyClass sut = fixture.CreateAnonymous<MyClass>();
// Exercise system
int result = sut.Echo(expectedNumber);
// Verify outcome
Assert.AreEqual<int>(expectedNumber, result, "Echo");
// Teardown
}
Is there such a tool in the Java world?
Edit:
I tried QuickCheck and while it managed to do something like what I was looking for:
import net.java.quickcheck.Generator;
import net.java.quickcheck.generator.PrimitiveGenerators;
import net.java.quickcheck.generator.support.ObjectGeneratorImpl;
public class Main {
interface Test{
String getTestValue();
}
public static void main(String[] args) {
Generator<String> stringGen = PrimitiveGenerators.strings(5, 100);
Generator<Integer> intGen = PrimitiveGenerators.integers(5, 20);
ObjectGeneratorImpl<Test> g = new ObjectGeneratorImpl<>(Test.class);
g.on(g.getRecorder().getTestValue()).returns(stringGen);
for (int i = 0; i < intGen.next(); i++) {
System.out.println("value of testValue is: " + g.next().getTestValue());
}
}
}
The tool seems to work only with interfaces. If I change Test to be a class and the method to a field, the generator throws an exception that only interfaces are supported.
I sincerely hope that there is something better, especially since the documentation is seriously lacking.
해결책
There is a Java implementation of QuickCheck, which has APIs for generating test data:
http://java.net/projects/quickcheck/pages/Home
I'm not too familiar with AutoFixture, and I suspect that QuickCheck is a slightly different kind of test framework, but maybe it is useful for solving your specific problem.
다른 팁
There's also JFixture which is available on github and published to maven central.
This is still under active development, and feature requests are being honoured.
Ivan,
I started a project focused on reimplementing core features of AutoFixture in java. AutoFixture has certainly a lot of features, so I need to prioritize which ones to implement first and which ones not to bother implementing at all. As the project is just started, I welcome testing, defect reports and feature requests.
I am using JFixture along Mockito.spy() for that ;)
Let's see an example how to do something that it would be trivial with AutoFixture and C#. The idea here is to generate random data in your object except for some specific methods that need to have specific values. It is interesting I didn't find that somewhere stated.. This technique eliminates the "Arrange" part of your unit tests to be a small number of lines and in addition focuses on what values need to be specific for this unit test to pass
public class SomeClass {
public int id; //field I care
public String name; // fields I don't care
public String description; //fields I don't care
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String getDescription(){
return description;
}
public void setDescirption(String description){
this.description = description;
}
}
public static void main(String args[]){
JFixture fixture = new JFixture();
fixture.customise().circularDependencyBehaviour().omitSpecimen(); //omit circular dependencies
fixture.customise().noResolutionBehaviour().omitSpecimen(); // omit methods that cannot be resolved
SomeClass entity = fixture.create(SomeClass.class);
SomeClass mock = Mockito.spy(entity);
Mockito.when(mock.getId()).thenReturn(3213);
System.out.println(mock.getId()); // always 3213
System.out.println(mock.getName()); // random
System.out.println(mock.getDescription()); //random
}
This prints:
3213
name9a800265-d8ef-4be9-bd45-f0b62f791d9c
descriptiona9f9245f-eba1-4805-89e3-308ef69e7091
Try object factory. It is open sourced on github. It can create random Java objects in just a single line of code. And it is highly configurable.
Example:
ObjectFactory rof = new ReflectionObjectFactory();
String str = rof.create(String.class);
Customer cus = rof.create(Customer.class);
It is also available in Maven Central Repository.
ObjectGenerator is more of an experimental feature:
ObjectGenerator<Test> objects = PrimitiveGenerators.objects(Test.class);
objects.on(objects.getRecorder().getTestValue()).returns(PrimitiveGenerators.strings());
Test next = objects.next();
System.out.println(next.getTestValue());
I'd prefer a simple Generator implementation:
class TestGenerator implements Generator<Test>{
Generator<String> values = PrimitiveGenerators.strings();
@Override public Test next() {
return new TestImpl(values.next());
}
}
Yet Another QuickCheck for Java is another tool you may probably take a look.
It is very integrated with JUnit (it supports tests with parameters, annotations to configure the generated objects and so on).
It has a lot of generators (all of quickcheck, and some specific to OOP, such as interfaces, abstract classes and singleton generators), and you can define your own ones. There is also a constructor-based generator.
Currently is in alpha status, but if you take a look to the downloads page you'll see a basic documentation.