misk icon indicating copy to clipboard operation
misk copied to clipboard

Structure MiskApplication to be testable

Open adrw opened this issue 7 years ago • 3 comments

Every service implements a default MiskApplication interface by adding necessary modules.

Every service also creates injector tests so that the requirements of modules can be verified in tests, not only when the service is run.

interface MiskApplication {
  fun modules(environment: Environment) : List<Module>
}

class UrlShortenerAppTest {
  fun createsInjectorInProduction() {
    val extraConfig = """
      dajfdkafdslkaf:

    """

    // If it fails to create the injector, we know the production is missing a module.
    Guice.createInjector(UrlShortenerApp().modules(Environment.PRODUCTION))
  }

  fun createsInjectorInStaging() {
    // If it fails to create the injector, we know the production is missing a module.
    Guice.createInjector(UrlShortenerApp().modules(Environment.STAGING))
  }

  fun createsInjectorInTest() {
    // If it fails to create the injector, we know the production is missing a module.
    Guice.createInjector(UrlShortenerApp().modules(Environment.TESTING))
  }
}

class UrlShortenerApp : com.squareup.cashurlshortener.service.MiskApplication {
  override fun modules(environment: Environment): List<Module> {
    SkimLogging.configure()
    listOf(
        CashUrlshortenerModule(environment),
        CashUrlshortenerServiceModule()
    )
  }
}

fun main(args: Array<String>) {
  MiskApplication(UrlShortenerApp()).run(args)
}

adrw avatar Oct 23 '18 18:10 adrw

I'm pretty strongly against this. Square's internal service container works this way and introducing conditionality / modality into the already complicated process of Guice bindings creates an initialization system that is nearly impossible to reason about.

mmihic avatar Oct 23 '18 18:10 mmihic

Other than starting the service, there doesn't seem to be another way to test that creating the Guice injector won't fail. Not having a way to test this has already caused a lot of headaches when deploying services with missing multibindings, new Misk or other module requirements, or other Guice issues.

This doesn't change the simplicity of running a service or introduce multiple injectors. It only tests that the injector creation will be successful in different environments.

adrw avatar Oct 24 '18 19:10 adrw

I'm not opposed to the goal, just the solution. This both introduces and formalizes (almost as best practice) having conditional logic to install different bindings depending on the environment. We have a similar mechanism in the in-house service container which allows for creating different modules on a per-environment basis and it becomes almost impossible to know what is actually getting installed. I might be ok with this if we ensure that environment level switches only exist at the application layer, and that modules themselves never have logic that is conditional based on environment.

mmihic avatar Oct 25 '18 13:10 mmihic