CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-scala-js--scalajs-junit-test-runtime

JUnit test runtime for Scala.js - provides the runtime infrastructure for running JUnit tests compiled with Scala.js

Pending
Overview
Eval results
Files

test-assumptions.mddocs/

Test Assumptions

The Assume object provides methods for conditional test execution. When assumptions fail, tests are skipped rather than failing, making them ideal for tests that depend on specific environmental conditions or prerequisites.

Core Assumption Methods

Boolean Assumptions

object Assume {
  def assumeTrue(b: Boolean): Unit
  def assumeTrue(message: String, b: Boolean): Unit
  def assumeFalse(b: Boolean): Unit
  def assumeFalse(message: String, b: Boolean): Unit
}

Usage:

import org.junit.Assume._

class EnvironmentDependentTest {
  @Test
  def shouldRunOnLinux(): Unit = {
    assumeTrue("Test only runs on Linux", System.getProperty("os.name").contains("Linux"))
    
    // This test only runs if we're on Linux
    val result = linuxSpecificOperation()
    assertNotNull(result)
  }
  
  @Test
  def shouldSkipInCI(): Unit = {
    assumeFalse("Skip in CI environment", System.getenv("CI") != null)
    
    // This test is skipped in CI environments
    performSlowLocalTest()
  }
}

Null Assumptions

def assumeNotNull(objects: AnyRef*): Unit

Usage:

@Test
def shouldWorkWithExternalService(): Unit = {
  val apiKey = System.getenv("API_KEY")
  val serviceUrl = System.getenv("SERVICE_URL")
  
  assumeNotNull("External service configuration required", apiKey, serviceUrl)
  
  // Test only runs if both environment variables are set
  val client = new ExternalServiceClient(apiKey, serviceUrl)
  val response = client.ping()
  assertEquals("OK", response.getStatus())
}

Hamcrest Matcher Assumptions

def assumeThat[T](actual: T, matcher: Matcher[T]): Unit
def assumeThat[T](message: String, actual: T, matcher: Matcher[T]): Unit

Usage:

import org.hamcrest.CoreMatchers._

@Test
def shouldRunWithSufficientMemory(): Unit = {
  val runtime = Runtime.getRuntime
  val maxMemory = runtime.maxHeapSize()
  
  assumeThat("Need at least 1GB heap", maxMemory, is(greaterThan(1024 * 1024 * 1024L)))
  
  // Test only runs with sufficient memory
  performMemoryIntensiveOperation()
}

@Test
def shouldWorkWithSpecificJavaVersion(): Unit = {
  val javaVersion = System.getProperty("java.version")
  
  assumeThat("Java 11+ required", javaVersion, not(startsWith("1.8")))
  
  // Test skipped on Java 8
  useJava11Features()
}

Exception Assumptions

def assumeNoException(e: Throwable): Unit
def assumeNoException(message: String, e: Throwable): Unit

Usage:

@Test
def shouldConnectToDatabase(): Unit = {
  var connection: Connection = null
  var connectionError: Throwable = null
  
  try {
    connection = DriverManager.getConnection(databaseUrl)
  } catch {
    case e: SQLException => connectionError = e
  }
  
  assumeNoException("Database must be available", connectionError)
  
  // Test only runs if database connection succeeded
  val result = connection.createStatement().executeQuery("SELECT 1")
  assertTrue(result.next())
}

Assumption vs Assertion Behavior

Assumptions - Skip Tests

@Test
def assumptionExample(): Unit = {
  assumeTrue(false) // Test is SKIPPED
  fail("This is never reached")
}

Assertions - Fail Tests

@Test
def assertionExample(): Unit = {
  assertTrue(false) // Test FAILS
  fail("This is never reached")
}

Common Use Cases

Platform-Specific Tests

class PlatformSpecificTest {
  @Test
  def shouldRunOnWindows(): Unit = {
    assumeTrue(System.getProperty("os.name").toLowerCase().contains("windows"))
    // Windows-specific test logic
  }
  
  @Test 
  def shouldRunOnUnix(): Unit = {
    val os = System.getProperty("os.name").toLowerCase()
    assumeTrue(os.contains("linux") || os.contains("mac"))
    // Unix-specific test logic
  }
}

Environment Configuration Tests

class ConfigurationTest {
  @Test
  def shouldTestWithRedisEnabled(): Unit = {
    assumeTrue("Redis integration tests", 
      System.getProperty("test.redis.enabled", "false").toBoolean)
    
    val redis = new RedisClient()
    redis.set("key", "value")
    assertEquals("value", redis.get("key"))
  }
  
  @Test
  def shouldTestProductionConfig(): Unit = {
    assumeThat("Production profile required", 
      System.getProperty("spring.profiles.active"), is("production"))
    
    // Test production-specific configuration
  }
}

Resource Availability Tests

class ResourceDependentTest {
  @Test
  def shouldTestWithExternalService(): Unit = {
    var serviceAvailable = false
    try {
      val socket = new Socket("external-service.com", 80)
      socket.close()
      serviceAvailable = true
    } catch {
      case _: IOException => // Service not available
    }
    
    assumeTrue("External service must be reachable", serviceAvailable)
    
    // Test external service integration
    val client = new ExternalServiceClient()
    val response = client.getData()
    assertNotNull(response)
  }
}

Java Version Compatibility

class VersionCompatibilityTest {
  @Test
  def shouldUseJava11Features(): Unit = {
    val version = System.getProperty("java.version")
    assumeThat("Java 11+ required for this test", 
      version, not(anyOf(startsWith("1.6"), startsWith("1.7"), startsWith("1.8"))))
    
    // Use Java 11+ features
    val result = List.of("a", "b", "c") // Java 9+ List.of
    assertEquals(3, result.size())
  }
}

Exception Handling

When assumptions fail, they throw AssumptionViolatedException:

class AssumptionViolatedException(message: String) extends RuntimeException

This exception is caught by the test runner and causes the test to be marked as "skipped" rather than "failed".

Internal Implementation:

// When assumption fails
if (!condition) {
  throw new AssumptionViolatedException(message)
}

Integration with Test Runners

Test runners handle assumption violations specially:

  • JUnit Runner: Reports test as "ignored" or "skipped"
  • IDE Integration: Shows skipped tests with different visual indicator
  • Build Tools: Count skipped tests separately from passed/failed
  • CI/CD: Skipped tests don't cause build failures

Best Practices

  1. Use for Environmental Dependencies: Skip tests when external resources aren't available
  2. Provide Clear Messages: Always include descriptive messages explaining why tests are skipped
  3. Document Assumptions: Make test requirements clear in test names and documentation
  4. Avoid Overuse: Don't use assumptions to hide poorly written tests
  5. Consider Test Categories: Use JUnit categories or tags as alternative to assumptions
  6. Validate Early: Put assumptions at the beginning of test methods

Assumptions vs Test Categories

Assumptions (runtime checking):

@Test
def shouldTestSlowOperation(): Unit = {
  assumeTrue("Slow tests enabled", System.getProperty("test.slow", "false").toBoolean)
  performSlowOperation()
}

Categories (compile-time filtering):

@Category(Array(classOf[SlowTests]))
@Test
def shouldTestSlowOperation(): Unit = {
  performSlowOperation()
}

Use assumptions when the decision to skip depends on runtime conditions. Use categories when the decision can be made at build time.

Install with Tessl CLI

npx tessl i tessl/maven-org-scala-js--scalajs-junit-test-runtime

docs

array-assertions.md

core-assertions.md

exception-handling.md

hamcrest-matchers.md

index.md

test-assumptions.md

test-lifecycle.md

test-runners.md

tile.json