question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Consider auto-generating assertThat and subject factory for custom subjects

See original GitHub issue

Currently a minimal Truth Subject requires four operations: a constructor, an assertion method, and two static methods for accessing the subject: assertThat and a subject factory (see extension page).

Would it be possible to auto-generate these methods and, possibly, accumulate all custom assertThat overloads in a single place, to cut down the number or operations the developer has to add to a custom subject, and encourage creating custom Subjects even if a single assertion method is needed?

For instance,

@AutoSubject(factoryName = "employees")
public final class EmployeeSubject extends Subject {

  private final Employee actual;

  // The constructor needs to be public if the class with `assertThat`
  // might be outside of its package
  public EmployeeSubject(FailureMetadata failureMetadata, @NullableDecl Employee subject) {
    super(failureMetadata, subject);
    this.actual = subject;
  }

  // User-defined test assertion SPI below this point

  public void hasName(String name) {
    check("name()").that(actual.name()).isEqualTo(name);
  }
}

Will generate these two methods:

  // User-defined entry point
  public static EmployeeSubject assertThat(@NullableDecl Employee employee) {
    return assertAbout(EMPLOYEE_SUBJECT_FACTORY).that(employee);
  }

  // Static method for getting the subject factory (for use with assertAbout())
  public static Subject.Factory<EmployeeSubject, Employee> employees() {
    return EMPLOYEE_SUBJECT_FACTORY;
  }

  // Boiler-plate Subject.Factory for EmployeeSubject
  private static final Subject.Factory<EmployeeSubject, Employee> EMPLOYEE_SUBJECT_FACTORY =
      EmployeeSubject::new;

As a new user of Truth, I can’t say if such implementations are common enough so that it makes sense to generate them. There are also other considerations:

  1. Visibility — if there are subjects for package-private types in several packages, the Truth won’t be able to produce a single file with all assertions. What shall it produce in this case — a file per subject, or per package?
  2. Discoverability — if Truth produces a single file with all assertions (which might not always work ^), it is trivial to import it knowing its name. But if it generates multiple files, it might be more difficult for the end-user to discover them.

#251, which suggested generating the factory, is likely related.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:1
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

3reactions
cpovirkcommented, Jul 24, 2019

Thanks. This is something that we’ve given a little thought to in the past. I’ll try to summarize here.

The boilerplate is definitely unfortunate. While you can cut the 2 methods down to this…

  public static EmployeeSubject assertThat(Employee employee) {
    return assertAbout(employees()).that(employee);
  }

  public static Factory<EmployeeSubject, Employee> employees() {
    return EmployeeSubject::new;
  }

…so that there’s no need for EMPLOYEE_SUBJECT_FACTORY, that’s still a bunch of boilerplate (on top of the constructor and field, plus the actual assertion methods, as you note above).

On top of that, there’s the possibility that we could generate the assertion methods themselves in straightforward cases (like the name case above).

For those reasons, I do think we will look into this eventually.

I say only “eventually,” though, for a few reasons:

  • First, we threw some extra effort into Truth to release 1.0, but now we want to let things settle for a little to get a better idea of what the Next Big Thing will be for Truth – possibly including features like this.
  • If we decide to take the more ambitious route of generating assertion methods, too, then there are a lot more design questions that we’ll have to resolve. (You mentioned a couple design questions already, as did @talios.)
  • Finally, there are some specific technical issues around annotation processors (which seems to be the approach you have in mind here?) that generate public API. The likely outcome of that is that any autogenerator we provided would be more of an “old-fashioned” code generator. (Such a generator could still be wired up as part of a build for users who want that, but it might be trickier.)

A little more on annotation processors that generate public API, cribbed from some internal documentation on the topic:

  • Users may be surprised when they don’t see assertThat or employees defined in the source.
  • IDEs’ incremental compilation often has a harder time with annotation processors. Similarly, build systems may need to fall back to a slow path that includes running annotation processors and forcing all dependent targets to wait to build.
  • Refactorings can be harder.
  • Generated code is usually harder to document. (To be fair, there’s usually little to write about methods like assertThat, and a code generator might do a better job of filling in a little boilerplate doc than a human would.)
2reactions
astubbscommented, Nov 3, 2021

As per the PR, this is now available here: https://github.com/astubbs/truth-generator as a pre-release SNAPSHOT that can be installed locally. Will work on getting it into repo1 soon.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Extensions to Truth
Extension points. Truth is configurable in multiple ways, including: custom failure behaviors; custom correspondences; custom assertion methods.
Read more >
8. Contract DSL - Spring Cloud
Spring Cloud Contract supports defining multiple contracts in a single file. The following is a complete example of a Groovy contract definition: The...
Read more >
DrJava User Documentation
custom configuration file, rather than the .drjava file stored in your home ... persons to whom the Software is furnished to do so,...
Read more >
Jdbi 3 Developer Guide
", 4, "Alice"); assertThat(count).isOne();. To further customize, use createUpdate : int count = handle.createUpdate ...
Read more >
Diff - stable-2.15^2..stable-2.15 - gerrit - Git at Google
+ +[[topic]] +== Topics + +Changes can be grouped by topics. Topics make it easier to find related ... If set, consider to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found