首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >联合仲裁的jqwik策略

联合仲裁的jqwik策略
EN

Stack Overflow用户
提问于 2022-11-22 18:48:23
回答 1查看 28关注 0票数 0

(上下文:我在基于属性的测试方面的背景主要来自scala的scalacheck库,jqwik中某些类型和注释的使用感觉有点不同,还有几个范例我还不太了解。)

我不知道如何最好地组合现有的原语类型的Arbitrary定义,以产生一个可重用的任意(多个@Property或测试类所需的)任意的,这些任意构建在我定义的其他Aribtrary定义之上。

考虑到这一点可能要清楚得多,举个例子:

代码语言:javascript
运行
复制
// assume this has a builder pattern or all-args constructor.
// consider this is some sort of core domain object that I need in various 
// test suites
public class MyComplexClass {
  private final String id; // positive-integer shaped
  private final String recordId; // uuid-shaped
  private final String creatorId; // positive-integer shaped
  private final String editorId; // positive-integer shaped
  private final String nonce; // uuid-shaped
  private final String payload; // random string
}

我的直觉是定义生成UUID类字符串的Aribrary<String>,以及生成正整数字符串的另一个字符串,类似于:

代码语言:javascript
运行
复制
public class MyArbitraries {
  public Arbitrary<String> arbUuidString() {
                return Combinators.combine(
                            Arbitraries.longs(), Arbitraries.longs(), Arbitraries.of(Set.of('8', '9', 'a', 'b')))
                    .as((l1, l2, y) -> {
                        StringBuilder b = new StringBuilder(new UUID(l1, l2).toString());
                        b.setCharAt(14, '4');
                        b.setCharAt(19, y);
                        return UUID.fromString(b.toString());
                    });
  }

  public Arbitrary<String> arbNumericIdString() {
    return Arbitraries.shorts().map(Math::abs).map(i -> "" + i);
  }
}

但是,我不确定如何最好地利用这些方法来生成Arbitrary< MyComplexClass>。我想要这样的东西:

代码语言:javascript
运行
复制
public class MyDomain extends DomainContextBase {
  @Provider
  public Arbitrary<MyComplexClass> arbMyComplexClass() {
    return Builders.withBuilder(MyComplexClass::newBuilder)
      // best way to reference these?!
      .use(arbNumericIdString()).in(MyComplexClass.Builder::setId)
      .use(arbUuidString()).in(MyComplexClass.Builder::setCreatorId)
      // etc.
    .build(MyComplexClass.Builder::build);
  }
}

我在这里的理解是:

  • I不能使用@ForAll‘注入’或提供这些仲裁器,因为只有在@Property-annotated方法
  • 中才支持ForAll。由于类似的原因,在这里不能使用@Domain,原因类似:

H 117我不能真正使用ArbitrarySupplier或类似于这里没有明显的“类型”,它主要是一串字符串<H 219F 220

创建静态Arbitrary<String>函数并直接调用它们是最好的选择吗?

EN

回答 1

Stack Overflow用户

发布于 2022-11-23 08:34:56

一个最初的评论是:@ForAll也适用于带有@Provide注解的方法和域。下面是一个简单的例子:

代码语言:javascript
运行
复制
class MyDomain extends DomainContextBase {

    @Provide
    public Arbitrary<String> strings(@ForAll("lengths") int length) {
        return Arbitraries.strings().alpha().ofLength(length);
    }

    @Provide
    public Arbitrary<Integer> lengths() {
        return Arbitraries.integers().between(3, 10);
    }

    // Will not be used by strings() method
    @Provide
    public Arbitrary<Integer> negatives() {
        return Arbitraries.integers().between(-100, -10);
    }

}

class MyProperties {
    @Property(tries = 101)
    @Domain(MyDomain.class)
    public void printOutAlphaStringsWithLength3to10(@ForAll String stringsFromDomain) {
        System.out.println(stringsFromDomain);
    }
}

可能令人困惑的是,@ForAll("myString")中的字符串引用只在本地计算(类本身、超类和包含类)。为了防止基于字符串的引用魔术,这是有目的的;首先必须回到字符串中--因为Java注释中不能使用“方法参考”--这已经够糟糕的了。

至于你的具体问题:

是创建静态任意函数并直接调用它们的最佳选择吗?

我认为这是一种“足够好”的方法,用于在单个域中或当您有几个从公共超类继承的相关域时共享生成器。

当您想要在不相关的域之间共享生成器时,您必须这样做:

type.

  • Introduce

  • 使用基于类型的解析:为RecordIdUUIDString等事物引入值类型。然后您可以使用域(或注册的ArbitraryProviders )来生成基于注释的不同类型的变体。然后,可以在provider方法或任意提供程序中检查注释。下面是一个例子:

代码语言:javascript
运行
复制
class MyNumbers extends DomainContextBase {
    @Provide
    Arbitrary<Integer> numbers() {
        return Arbitraries.integers().between(0, 255);
    }
}

@Domain(MyNumbers.class)
class MyDomain extends DomainContextBase {

    @Target({ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @interface Name {}

    @Target({ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @interface HexNumber {}

    @Provide
    public Arbitrary<String> names(TypeUsage targetType) {
        if (targetType.isAnnotated(Name.class)) {
            return Arbitraries.strings().alpha().ofLength(5);
        }
        return null;
    }

    @Provide
    public Arbitrary<String> numbers(TypeUsage targetType) {
        if (targetType.isAnnotated(HexNumber.class)) {
            return Arbitraries.defaultFor(Integer.class).map(Integer::toHexString);
        }
        return null;
    }
}

@Property(tries = 101)
@Domain(MyDomain.class)
public void generateNamesAndHexNumbers(
        @ForAll @MyDomain.Name String aName,
        @ForAll @MyDomain.HexNumber String aHexNumber
) {
    System.out.println(aName);
    System.out.println(aHexNumber);
}

此示例还展示了如何通过注释域实现类并具有参数注入或使用MyNumbers在另一个域(MyDomain)中使用一个域(MyDomain)。

但是,对于共享jqwik中缺少的仲裁,可能有一个有用的特性。jqwik团队对任何建议都很满意。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74537664

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档