我想使用Guice和GuiceBerry将非静态遗留服务注入到工厂类中。然后,我想将该工厂注入到参数化JUnit测试中。
但是,问题是JUnit要求@Parameters方法是静态的。
工厂示例:
@Singleton
public class Ratings {
@Inject
private RatingService ratingService;
public Rating classicRating() {
return ratingService.getRatingById(1002)
}
// More rating factory methods
}示例测试使用情况:
@RunWith(Parameterized.class)
public class StaticInjectParamsTest {
@Rule
public GuiceBerryRule guiceBerryRule = new GuiceBerryRule(ExtendedTestMod.class)
@Inject
private static Ratings ratings;
@Parameter
public Rating rating;
@Parameters
public static Collection<Rating[]> ratingsParameters() {
return Arrays.asList(new Rating[][]{
{ratings.classicRating()}
// All the other ratings
});
}
@Test
public void shouldWork() {
//Use the rating in a test
}
}我尝试请求工厂方法的静态注入,但是Parameters方法在GuiceBerry @Rule之前被调用。我还考虑过只使用评级的Id作为参数,但我想找到一个可重用的解决方案。也许我的方法有缺陷?
发布于 2015-06-18 16:09:55
我的解决方案是添加一个包装整数的RatingId类,并创建一个工厂RatingIds,然后我可以返回静态,并将其用作参数。我在RatingService接口中重载了RatingService方法以接受新的RatingId类型,然后将评级服务注入到我的测试中并直接使用它。
新增工厂:
public class RatingIds {
public static RatingId classic() {
return new RatingId(1002);
}
// Many more
}测试:
@RunWith(Parameterized.class)
public class StaticInjectParamsTest {
@Rule
public GuiceBerryRule guiceBerryRule = new GuiceBerryRule(ExtendedTestMod.class)
@Inject
private RatingService ratingService
@Parameter
public RatingId ratingId;
@Parameters
public static Collection<RatingId[]> ratingsParameters() {
return Arrays.asList(new RatingId[][]{
{RatingIds.classic()}
// All the other ratings
});
}
@Test
public void shouldWork() {
Rating rating = ratingService.getRatingById(ratingId.getValue())
//Use the rating in a test
}
}发布于 2015-06-18 00:44:27
不幸的是,JUnit需要能够在运行任何测试之前枚举所有测试,因此必须在规则之前调用参数方法。
您可以为评级类型定义一个枚举::
@RunWith(Parameterized.class)
public class StaticInjectParamsTest {
@Rule
public GuiceBerryRule guiceBerryRule
= new GuiceBerryRule(ExtendedTestMod.class);
@Inject
private Ratings ratings;
@Parameter
public RatingType ratingType;
@Parameters
public static Collection<RatingType> types() {
return Arrays.asList(RatingType.values());
}
@Test
public void shouldWork() {
Rating rating = ratings.get(ratingType);
// Use the rating in a test
}
}编辑:enum的代码:
public enum RatingType {
CLASSIC(1002),
COMPLEX(1020);
private final int ratingId;
private RatingType(int ratingId) {
this.ratingId = ratingId;
}
// option 1: keep rating ID private by having a method like this
public get(RatingService ratingService) {
return ratingService.getRatingById(ratingId);
}
// option 2: have a package-scope accessor
int getRatingId() {
return ratingId;
}
}编辑:如果您使用选项2,那么您将添加一个新方法,从一个Rating获得一个RatingType,该方法将委托给传递ratingId的服务
@Singleton
public class Ratings {
@Inject
private RatingService ratingService;
public Rating getRating(RatingType ratingType) {
return ratingService.getRatingById(
ratingType.getRatingId());
}
// More rating factory methods
}如果您不希望RatingType在您的公共API中,您可以在测试中定义它,并在枚举中有一个名为getRating()的方法。
public enum RatingType {
CLASSIC {
@Override public Rating getRating(Ratings ratings) {
return ratings.getClassicRating();
}
},
COMPLEX {
@Override public Rating getRating(Ratings ratings) {
return ratings.getComplexRating();
}
};
public abstract Rating getRating(Ratings ratings);
}还可以创建值类型,而不是枚举。
这假设您可以编写所有Rating实例都应该通过的测试。
如果您有一些公共测试,但是一些特定于评级的测试,我将创建一个包含公共测试的抽象基类和一个抽象createRating()方法,并对每个评级类型进行子类化。
发布于 2019-04-30 04:59:44
在您的情况下,生成的参数集的总数是预先已知的,但是构建参数本身需要一些上下文(例如,使用Spring的自动处理服务实例),您可以使用函数方法(使用junit5 &参数化)
显然,如果createParameter函数本身依赖于这样的contex:-/,则这是行不通的。
class MyTestClass {
// may be autowired, cannot be static but is required in parameter generation
SomeInstance instance;
private interface SomeParamBuilder { SomeParam build(SomeInstance i);}
private static Stream<Arguments> createParamterFactories() {
return Stream.of(
Arguments.of((SomeParamBuilder)(i)->
{
return new SomeParam(i);
})
);
}
// does not work, because SomeParam needs SomeInstance for construction
// which is not available in static context of createParameters.
//@ParameterizedTest(name = "[{index}] {0}")
//@MethodSource("createParameters")
//void myTest(SomeParam param) {
//}
@ParameterizedTest(name = "[{index}] {0}")
@MethodSource("createParamterFactories")
void myTest(SomeParamBuilder builder) {
SomeParam param = builder.build(instance);
// rest of your test code can use param.
}
}maven dep:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>https://stackoverflow.com/questions/30895711
复制相似问题