Skip to content

Commit f0ae1ac

Browse files
committed
feat: introduce factory-method instantiator
1 parent 5d908a0 commit f0ae1ac

7 files changed

Lines changed: 168 additions & 5 deletions

File tree

src/main/java/com/github/nylle/javafixture/SpecimenType.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.github.nylle.javafixture;
22

3+
import com.github.nylle.javafixture.instantiation.Builder;
4+
35
import java.lang.reflect.Constructor;
46
import java.lang.reflect.Method;
57
import java.lang.reflect.Modifier;

src/main/java/com/github/nylle/javafixture/Builder.java renamed to src/main/java/com/github/nylle/javafixture/instantiation/Builder.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
package com.github.nylle.javafixture;
1+
package com.github.nylle.javafixture.instantiation;
2+
3+
import com.github.nylle.javafixture.CustomizationContext;
4+
import com.github.nylle.javafixture.SpecimenFactory;
5+
import com.github.nylle.javafixture.SpecimenType;
26

37
import java.lang.annotation.Annotation;
48
import java.lang.reflect.InvocationTargetException;
@@ -10,7 +14,7 @@
1014

1115
import static java.util.stream.Collectors.toList;
1216

13-
public class Builder<T> {
17+
public class Builder<T> implements Instantiator<T> {
1418

1519
private final Method buildMethod;
1620
private final Method builderMethod;
@@ -31,7 +35,11 @@ public T invoke(SpecimenFactory specimenFactory, CustomizationContext customizat
3135
var builder = builderMethod.invoke(null, new Object[]{});
3236

3337
for (var method : findSetMethods()) {
34-
method.invoke(builder, new Object[]{specimenFactory.build(SpecimenType.fromClass(method.getGenericParameterTypes()[0])).create(customizationContext, new Annotation[0])});
38+
method.invoke(builder, new Object[]{
39+
specimenFactory
40+
.build(SpecimenType.fromClass(method.getGenericParameterTypes()[0]))
41+
.create(customizationContext, new Annotation[0])
42+
});
3543
}
3644

3745
return (T) buildMethod.invoke(builder, new Object[]{});
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.github.nylle.javafixture.instantiation;
2+
3+
import com.github.nylle.javafixture.CustomizationContext;
4+
import com.github.nylle.javafixture.SpecimenFactory;
5+
import com.github.nylle.javafixture.SpecimenType;
6+
7+
import java.lang.annotation.Annotation;
8+
import java.lang.reflect.Method;
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
12+
public class FactoryMethod<T> implements Instantiator<T> {
13+
14+
private final Method factoryMethod;
15+
private final SpecimenType<T> targetType;
16+
17+
public FactoryMethod(Method factoryMethod, SpecimenType<T> targetType) {
18+
this.factoryMethod = factoryMethod;
19+
this.targetType = targetType;
20+
}
21+
22+
public static <T> FactoryMethod<T> create(Method factoryMethod, SpecimenType<T> targetType) {
23+
return new FactoryMethod<>(factoryMethod, targetType);
24+
}
25+
26+
public T invoke(SpecimenFactory specimenFactory, CustomizationContext customizationContext) {
27+
try {
28+
List<Object> arguments = new ArrayList<>();
29+
for (int i = 0; i < factoryMethod.getParameterCount(); i++) {
30+
var genericParameterType = factoryMethod.getGenericParameterTypes()[i];
31+
var specimen = specimenFactory.build(targetType.isParameterized()
32+
? targetType.getGenericTypeArgument(i)
33+
: SpecimenType.fromClass(genericParameterType));
34+
var o = specimen.create(customizationContext, new Annotation[0]);
35+
arguments.add(o);
36+
}
37+
return (T) factoryMethod.invoke(null, arguments.toArray());
38+
} catch (Exception ex) {
39+
return null;
40+
}
41+
}
42+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.github.nylle.javafixture.instantiation;
2+
3+
import com.github.nylle.javafixture.CustomizationContext;
4+
import com.github.nylle.javafixture.SpecimenFactory;
5+
6+
public interface Instantiator<T> {
7+
8+
T invoke(SpecimenFactory specimenFactory, CustomizationContext customizationContext);
9+
10+
}

src/test/java/com/github/nylle/javafixture/BuilderTest.java renamed to src/test/java/com/github/nylle/javafixture/instantiation/BuilderTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
package com.github.nylle.javafixture;
1+
package com.github.nylle.javafixture.instantiation;
22

3+
import com.github.nylle.javafixture.Configuration;
4+
import com.github.nylle.javafixture.Context;
5+
import com.github.nylle.javafixture.CustomizationContext;
6+
import com.github.nylle.javafixture.SpecimenFactory;
7+
import com.github.nylle.javafixture.SpecimenType;
38
import com.github.nylle.javafixture.testobjects.ClassWithBuilder;
49
import org.junit.jupiter.api.Test;
510

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package com.github.nylle.javafixture.instantiation;
2+
3+
import com.github.nylle.javafixture.Configuration;
4+
import com.github.nylle.javafixture.Context;
5+
import com.github.nylle.javafixture.SpecimenFactory;
6+
import com.github.nylle.javafixture.SpecimenType;
7+
import com.github.nylle.javafixture.testobjects.factorymethod.FactoryMethodWithArgument;
8+
import com.github.nylle.javafixture.testobjects.factorymethod.FactoryMethodWithGenericArgument;
9+
import com.github.nylle.javafixture.testobjects.factorymethod.FactoryMethodWithoutArgument;
10+
import com.github.nylle.javafixture.testobjects.factorymethod.GenericClassWithFactoryMethodWithoutArgument;
11+
import org.junit.jupiter.api.DisplayName;
12+
import org.junit.jupiter.api.Test;
13+
14+
import java.nio.charset.Charset;
15+
import java.util.Optional;
16+
17+
import static com.github.nylle.javafixture.CustomizationContext.noContext;
18+
import static com.github.nylle.javafixture.SpecimenType.fromClass;
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
21+
class FactoryMethodTest {
22+
23+
@Test
24+
@DisplayName("returns instance of class using factory method without arguments")
25+
void factoryMethodWithoutArgument() throws NoSuchMethodException {
26+
var sut = FactoryMethod.<FactoryMethodWithoutArgument>create(FactoryMethodWithoutArgument.class.getDeclaredMethod("factoryMethod"), fromClass(FactoryMethodWithoutArgument.class));
27+
28+
var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());
29+
30+
assertThat(actual.getValue()).isEqualTo(42);
31+
}
32+
33+
@Test
34+
@DisplayName("returns instance of class using factory method with arguments")
35+
void returnsInstanceOfClassUsingFactoryMethodWithArguments() throws NoSuchMethodException {
36+
var sut = FactoryMethod.<FactoryMethodWithArgument>create(FactoryMethodWithArgument.class.getDeclaredMethod("factoryMethod", int.class), fromClass(FactoryMethodWithArgument.class));
37+
38+
var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());
39+
40+
assertThat(actual.getValue()).isNotNull();
41+
}
42+
43+
@Test
44+
@DisplayName("returns instance of class using factory method with generic argument")
45+
void factoryMethodWithGenericArgument() throws NoSuchMethodException {
46+
var sut = FactoryMethod.create(FactoryMethodWithGenericArgument.class.getDeclaredMethod("factoryMethod", Object.class), new SpecimenType<FactoryMethodWithGenericArgument<Integer>>() {});
47+
48+
var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());
49+
50+
assertThat(actual.getValue()).isNotNull();
51+
}
52+
53+
@Test
54+
@DisplayName("returns instance of abstract class using factory method without arguments")
55+
void returnsInstanceOfAbstractClassUsingFactoryMethod() throws NoSuchMethodException {
56+
var sut = FactoryMethod.create(Charset.class.getDeclaredMethod("defaultCharset"), new SpecimenType<Charset>() {});
57+
58+
var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());
59+
60+
assertThat(actual).isInstanceOf(Charset.class);
61+
}
62+
63+
@Test
64+
@DisplayName("returns instance of Optional using factory method with arguments")
65+
void createOptionalWithArgument() throws NoSuchMethodException {
66+
var sut = FactoryMethod.create(Optional.class.getDeclaredMethod("of", Object.class), new SpecimenType<Optional<String>>() {});
67+
68+
var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());
69+
70+
assertThat(actual).isInstanceOf(Optional.class);
71+
assertThat(actual).isNotEmpty();
72+
assertThat(actual.get()).isInstanceOf(String.class);
73+
}
74+
75+
@Test
76+
@DisplayName("returns instance of Optional using factory method without arguments")
77+
void createOptionalWithoutArgument() throws NoSuchMethodException {
78+
var sut = FactoryMethod.create(Optional.class.getDeclaredMethod("empty"), new SpecimenType<Optional<String>>() {});
79+
80+
var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());
81+
82+
assertThat(actual).isInstanceOf(Optional.class);
83+
assertThat(actual).isEmpty();
84+
}
85+
86+
@Test
87+
@DisplayName("returns instance of generic class using generic method without arguments")
88+
void genericNoArgumentFactoryMethod() throws NoSuchMethodException {
89+
var sut = FactoryMethod.create(GenericClassWithFactoryMethodWithoutArgument.class.getDeclaredMethod("factoryMethod"), new SpecimenType<GenericClassWithFactoryMethodWithoutArgument<Integer>>() {});
90+
91+
var actual = sut.invoke(new SpecimenFactory(new Context(Configuration.configure())), noContext());
92+
93+
assertThat(actual).isNotNull();
94+
assertThat(actual.getValue()).isEqualTo(42);
95+
}
96+
}

src/test/java/com/github/nylle/javafixture/testobjects/factorymethod/TestObjectWithNonPublicFactoryMethods.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
public class TestObjectWithNonPublicFactoryMethods {
44
private String value;
55

6-
protected static TestObjectWithNonPublicFactoryMethods privateStaticMethodReturningABoolean() {
6+
protected static TestObjectWithNonPublicFactoryMethods protectedStaticMethodReturningABoolean() {
77
return new TestObjectWithNonPublicFactoryMethods();
88
}
99

0 commit comments

Comments
 (0)