-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #214 from alejandrohdezma/munit-fixtures
Create alternative way to use testcontainers in MUnit using fixtures
- Loading branch information
Showing
5 changed files
with
482 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
205 changes: 205 additions & 0 deletions
205
...it/src/main/scala/com/dimafeng/testcontainers/munit/fixtures/TestContainersFixtures.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
package com.dimafeng.testcontainers.munit.fixtures | ||
|
||
import com.dimafeng.testcontainers.lifecycle.Stoppable | ||
import org.testcontainers.lifecycle.Startable | ||
import munit.Suite | ||
import munit.FunFixtures | ||
import munit.FunSuite | ||
import com.dimafeng.testcontainers.munit.TestContainersSuite | ||
import com.dimafeng.testcontainers.lifecycle.TestLifecycleAware | ||
|
||
trait TestContainersFixtures { self: FunSuite => | ||
|
||
/** | ||
* Creates a fixture that starts a single container before each test and stops | ||
* it after each test. | ||
* | ||
* @example | ||
* {{{ | ||
* class MysqlSpec extends FunSuite with TestContainersFixtures { | ||
* | ||
* val mysql = ForEachContainerFixture(MySQLContainer()) | ||
* | ||
* // You need to override `munitFixtures` and pass in your container fixture | ||
* override def munitFixtures = List(mysql) | ||
* | ||
* test("test case name") { | ||
* // Inside your test body you can do with your container whatever you want to | ||
* assert(mysql().jdbcUrl.nonEmpty) | ||
* } | ||
* } | ||
* }}} | ||
*/ | ||
class ForEachContainerFixture[T <: Startable with Stoppable](val container: T) | ||
extends Fixture[T]("ForEachTestContainers") { | ||
|
||
def apply(): T = container | ||
|
||
def afterContainerStart(container: T, context: BeforeEach): Unit = () | ||
|
||
def beforeContainerStop(container: T, context: AfterEach): Unit = () | ||
|
||
override def beforeEach(context: BeforeEach): Unit = { | ||
container.start() | ||
afterContainerStart(container, context) | ||
container match { | ||
case container: TestLifecycleAware => container.beforeTest(suiteDescription) | ||
case _ => // do nothing | ||
} | ||
} | ||
|
||
override def afterEach(context: AfterEach): Unit = { | ||
container match { | ||
case container: TestLifecycleAware => container.afterTest(suiteDescription, None) | ||
case _ => // do nothing | ||
} | ||
beforeContainerStop(container, context) | ||
container.stop() | ||
} | ||
|
||
} | ||
|
||
object ForEachContainerFixture { | ||
|
||
/** | ||
* Creates a fixture that starts a single container before each test and stops | ||
* it after each test. | ||
* | ||
* @example | ||
* {{{ | ||
* class MysqlSpec extends FunSuite with TestContainersFixtures { | ||
* | ||
* val mysql = ForEachContainerFixture(MySQLContainer()) | ||
* | ||
* // You need to override `munitFixtures` and pass in your container fixture | ||
* override def munitFixtures = List(mysql) | ||
* | ||
* test("test case name") { | ||
* // Inside your test body you can do with your container whatever you want to | ||
* assert(mysql().jdbcUrl.nonEmpty) | ||
* } | ||
* } | ||
* }}} | ||
*/ | ||
def apply[T <: Startable with Stoppable](container: T) = new ForEachContainerFixture[T](container) | ||
|
||
} | ||
|
||
/** | ||
* Creates a fixture that starts a single container before all test and stops | ||
* it after all test. | ||
* | ||
* @example | ||
* {{{ | ||
* class MysqlSpec extends FunSuite with TestContainersFixtures { | ||
* | ||
* val mysql = ForAllContainerFixture(MySQLContainer()) | ||
* | ||
* // You need to override `munitFixtures` and pass in your container fixture | ||
* override def munitFixtures = List(mysql) | ||
* | ||
* test("test case name") { | ||
* // Inside your test body you can do with your container whatever you want to | ||
* assert(mysql().jdbcUrl.nonEmpty) | ||
* } | ||
* } | ||
* }}} | ||
*/ | ||
class ForAllContainerFixture[T <: Startable with Stoppable](val container: T) | ||
extends Fixture[T]("ForAllTestContainers") { | ||
|
||
def apply(): T = container | ||
|
||
def afterContainerStart(container: T): Unit = () | ||
|
||
def beforeContainerStop(container: T): Unit = () | ||
|
||
override def beforeAll(): Unit = { | ||
container.start() | ||
afterContainerStart(container) | ||
} | ||
|
||
override def beforeEach(context: BeforeEach): Unit = container match { | ||
case container: TestLifecycleAware => container.beforeTest(suiteDescription) | ||
case _ => // do nothing | ||
} | ||
|
||
override def afterAll(): Unit = { | ||
beforeContainerStop(container) | ||
container.stop() | ||
} | ||
|
||
override def afterEach(context: AfterEach): Unit = container match { | ||
case container: TestLifecycleAware => container.afterTest(suiteDescription, None) | ||
case _ => // do nothing | ||
} | ||
|
||
} | ||
|
||
object ForAllContainerFixture { | ||
|
||
/** | ||
* Creates a fixture that starts a single container before all test and stops | ||
* it after all test. | ||
* | ||
* @example | ||
* {{{ | ||
* class MysqlSpec extends FunSuite with TestContainersFixtures { | ||
* | ||
* val mysql = ForAllContainerFixture(MySQLContainer()) | ||
* | ||
* // You need to override `munitFixtures` and pass in your container fixture | ||
* override def munitFixtures = List(mysql) | ||
* | ||
* test("test case name") { | ||
* // Inside your test body you can do with your container whatever you want to | ||
* assert(mysql().jdbcUrl.nonEmpty) | ||
* } | ||
* } | ||
* }}} | ||
*/ | ||
def apply[T <: Startable with Stoppable](container: T) = new ForAllContainerFixture[T](container) | ||
|
||
} | ||
|
||
object ContainerFunFixture { | ||
|
||
/** | ||
* Creates a fun-fixture that starts a single container before each test and stops | ||
* it after each test. | ||
* | ||
* @example | ||
* {{{ | ||
* class MysqlSpec extends FunSuite with TestContainersFixtures { | ||
* | ||
* val mysql = ContainerFunFixture(MySQLContainer()) | ||
* | ||
* mysql.test("test case name") { container => | ||
* // Inside your test body you can do with your container whatever you want to | ||
* assert(container.jdbcUrl.nonEmpty) | ||
* } | ||
* } | ||
* }}} | ||
*/ | ||
def apply[T <: Startable with Stoppable](container: T) = FunFixture[T]( | ||
setup = { _ => | ||
container.start(); | ||
container match { | ||
case tla: TestLifecycleAware => tla.beforeTest(suiteDescription) | ||
case _ => // do nothing | ||
} | ||
container | ||
}, teardown = { c => | ||
c match { | ||
case tla: TestLifecycleAware => tla.afterTest(suiteDescription, None) | ||
case _ => // do nothing | ||
} | ||
c.stop() | ||
} | ||
) | ||
|
||
} | ||
|
||
private val suiteDescription = TestContainersSuite.createDescription(self) | ||
|
||
} |
77 changes: 77 additions & 0 deletions
77
...t/src/test/scala/com/dimafeng/testcontainers/munit/fixtures/ContainerFunFixtureSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.dimafeng.testcontainers.munit.fixtures | ||
|
||
import java.util.Optional | ||
|
||
import com.dimafeng.testcontainers.ContainerDef | ||
import com.dimafeng.testcontainers.munit.SampleContainer | ||
import com.dimafeng.testcontainers.munit.SampleContainer.SampleJavaContainer | ||
import com.dimafeng.testcontainers.munit.fixtures.ContainerFunFixtureSpec._ | ||
import munit.{FunSuite, MUnitRunner, Suite} | ||
import org.junit.runner.notification.RunNotifier | ||
import org.mockito.ArgumentMatchers.any | ||
import org.mockito.Mockito.{times, verify} | ||
import org.mockito.{ArgumentMatchers, Mockito} | ||
import org.scalatestplus.mockito.MockitoSugar | ||
import com.dimafeng.testcontainers.Container | ||
|
||
class ContainerFunFixtureSpec extends FunSuite with MockitoSugar { | ||
test("call all appropriate methods of the containers") { | ||
val container = mock[SampleJavaContainer] | ||
|
||
val spec = new TestSpec(assert(cond = true), SampleContainer(container)) | ||
run(spec) | ||
|
||
verify(container).beforeTest(any()) | ||
verify(container).start() | ||
verify(container).afterTest(any(), ArgumentMatchers.eq(Optional.empty())) | ||
verify(container).stop() | ||
} | ||
|
||
test("call all appropriate methods of the containers if assertion fails") { | ||
val container = mock[SampleJavaContainer] | ||
|
||
val spec = new TestSpec(assert(cond = false), SampleContainer(container)) | ||
|
||
run(spec) | ||
|
||
verify(container).beforeTest(any()) | ||
verify(container).start() | ||
verify(container).afterTest(any(), ArgumentMatchers.eq(Optional.empty())) | ||
verify(container).stop() | ||
} | ||
|
||
test("start and stop containers before and after each test case") { | ||
val container = mock[SampleJavaContainer] | ||
|
||
val spec = new MultipleTestsSpec(assert(cond = true), SampleContainer(container)) | ||
run(spec) | ||
|
||
verify(container, times(2)).beforeTest(any()) | ||
verify(container, times(2)).start() | ||
verify(container, times(2)).afterTest(any(), any()) | ||
verify(container, times(2)).stop() | ||
} | ||
|
||
} | ||
|
||
object ContainerFunFixtureSpec { | ||
protected abstract class ContainerSpec extends FunSuite with TestContainersFixtures | ||
|
||
protected class TestSpec(testBody: => Unit, container: Container) extends ContainerSpec { | ||
val containerFixture = ContainerFunFixture(container) | ||
|
||
containerFixture.test("test") { _ => testBody} | ||
} | ||
|
||
protected class MultipleTestsSpec(testBody: => Unit, container: Container) extends ContainerSpec { | ||
val containerFixture = ContainerFunFixture(container) | ||
|
||
containerFixture.test("test1") { _ => testBody} | ||
containerFixture.test("test2") { _ => testBody} | ||
} | ||
|
||
private def run(res: Suite): Unit = { | ||
val notifier = new RunNotifier() | ||
new MUnitRunner(res.asInstanceOf[Suite].getClass, () => res).run(notifier) | ||
} | ||
} |
Oops, something went wrong.