From 44f7b6d699486672c3607a3bba9a889e6ad3b8d7 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Thu, 3 Sep 2015 22:15:47 +0300 Subject: [PATCH] Unit testing API: better mapping on JUnit, proper formatting assertion details when message is not specified #KT-8929 Fixed Sensible default message for assertion methods. #KT-8314 Fixed Provide assertFailsWith also with KClass and reified type argument. --- js/js.libraries/src/qunit/core.kt | 2 +- js/js.libraries/src/stdlib/testCode.kt | 24 +--- .../testData/jsTester/jsTester.kt | 15 --- .../kunit/src/main/kotlin/junit/JUnit.kt | 14 +-- libraries/stdlib/src/kotlin/test/Test.kt | 110 ++++++++++-------- libraries/stdlib/src/kotlin/test/TestJVM.kt | 51 ++++---- 6 files changed, 102 insertions(+), 114 deletions(-) diff --git a/js/js.libraries/src/qunit/core.kt b/js/js.libraries/src/qunit/core.kt index 7be0a2e1fb2..94c1b88eead 100644 --- a/js/js.libraries/src/qunit/core.kt +++ b/js/js.libraries/src/qunit/core.kt @@ -5,5 +5,5 @@ package QUnit */ native -public fun ok(actual: Boolean, message: String): Unit = noImpl; +public fun ok(actual: Boolean, message: String?): Unit = noImpl; diff --git a/js/js.libraries/src/stdlib/testCode.kt b/js/js.libraries/src/stdlib/testCode.kt index 5309fc87507..887bd9e2973 100644 --- a/js/js.libraries/src/stdlib/testCode.kt +++ b/js/js.libraries/src/stdlib/testCode.kt @@ -17,27 +17,15 @@ public var asserter: Asserter = QUnitAsserter() public class QUnitAsserter(): Asserter { - public override fun assertTrue(message: String, actual: Boolean) { + public override fun assertTrue(lazyMessage: () -> String?, actual: Boolean) { + QUnit.ok(actual, lazyMessage()) + } + + public override fun assertTrue(message: String?, actual: Boolean) { QUnit.ok(actual, message) } - public override fun assertEquals(message: String, expected: Any?, actual: Any?) { - QUnit.ok(expected == actual, "$message. Expected <$expected> actual <$actual>") - } - - public override fun assertNotEquals(message: String, illegal: Any?, actual: Any?) { - QUnit.ok(illegal != actual, "$message. Illegal value: <$illegal>") - } - - public override fun assertNotNull(message: String, actual: Any?) { - QUnit.ok(actual != null, message) - } - - public override fun assertNull(message: String, actual: Any?) { - QUnit.ok(actual == null, message) - } - - public override fun fail(message: String) { + public override fun fail(message: String?) { QUnit.ok(false, message) } } \ No newline at end of file diff --git a/js/js.translator/testData/jsTester/jsTester.kt b/js/js.translator/testData/jsTester/jsTester.kt index 8a3d9e728bb..ff45832f97c 100644 --- a/js/js.translator/testData/jsTester/jsTester.kt +++ b/js/js.translator/testData/jsTester/jsTester.kt @@ -7,21 +7,6 @@ fun init() { } public class JsTestsAsserter() : Asserter { - public override fun assertTrue(message: String, actual: Boolean) { - assert(actual, message) - } - public override fun assertEquals(message: String, expected: Any?, actual: Any?) { - assert(actual == expected, "$message. Expected <$expected> actual <$actual>") - } - public override fun assertNotEquals(message: String, illegal: Any?, actual: Any?) { - assert(illegal != actual, "$message. Illegal value: <$illegal>") - } - public override fun assertNotNull(message: String, actual: Any?) { - assert(actual != null, message) - } - public override fun assertNull(message: String, actual: Any?) { - assert(actual == null, message) - } public override fun fail(message: String) { assert(false, message) } diff --git a/libraries/kunit/src/main/kotlin/junit/JUnit.kt b/libraries/kunit/src/main/kotlin/junit/JUnit.kt index 6d34bdf8ec8..ce0ef1b2599 100644 --- a/libraries/kunit/src/main/kotlin/junit/JUnit.kt +++ b/libraries/kunit/src/main/kotlin/junit/JUnit.kt @@ -4,27 +4,23 @@ import kotlin.test.Asserter import org.junit.Assert class JUnitAsserter : Asserter { - override fun assertEquals(message : String, expected : Any?, actual : Any?) { + override fun assertEquals(message : String?, expected : Any?, actual : Any?) { Assert.assertEquals(message, expected, actual) } - override fun assertNotEquals(message : String, illegal : Any?, actual : Any?) { + override fun assertNotEquals(message : String?, illegal : Any?, actual : Any?) { Assert.assertNotEquals(message, illegal, actual) } - override fun assertNotNull(message : String, actual : Any?) { + override fun assertNotNull(message : String?, actual : Any?) { Assert.assertNotNull(message, actual) } - override fun assertNull(message : String, actual : Any?) { + override fun assertNull(message : String?, actual : Any?) { Assert.assertNull(message, actual) } - override fun assertTrue(message : String, actual : Boolean) { - Assert.assertTrue(message, actual) - } - - override fun fail(message : String) { + override fun fail(message : String?) { Assert.fail(message) } } \ No newline at end of file diff --git a/libraries/stdlib/src/kotlin/test/Test.kt b/libraries/stdlib/src/kotlin/test/Test.kt index d0495780e13..2ad10a983a4 100644 --- a/libraries/stdlib/src/kotlin/test/Test.kt +++ b/libraries/stdlib/src/kotlin/test/Test.kt @@ -3,51 +3,49 @@ */ package kotlin.test -/** Asserts that the given [block] returns `true`. */ -public fun assertTrue(message: String, block: () -> Boolean) { - val actual = block() - asserter.assertTrue(message, actual) -} - -/** Asserts that the given [block] returns `true`. */ -public fun assertTrue(block: () -> Boolean): Unit = assertTrue("expected true", block) /** Asserts that the given [block] returns `false`. */ -public fun assertNot(message: String, block: () -> Boolean) { - assertTrue(message) { !block() } -} +@deprecated("Use assertFalse instead.", ReplaceWith("assertFalse(message, block)")) +public fun assertNot(message: String, block: () -> Boolean): Unit = assertFalse(message, block) /** Asserts that the given [block] returns `false`. */ -public fun assertNot(block: () -> Boolean): Unit = assertNot("expected false", block) +@deprecated("Use assertFalse instead.", ReplaceWith("assertFalse(null, block)")) +public fun assertNot(block: () -> Boolean): Unit = assertFalse(block = block) + +/** Asserts that the given [block] returns `true`. */ +public fun assertTrue(message: String? = null, block: () -> Boolean): Unit = assertTrue(block(), message) /** Asserts that the expression is `true` with an optional [message]. */ -public fun assertTrue(actual: Boolean, message: String = "") { - return assertEquals(true, actual, message) +public fun assertTrue(actual: Boolean, message: String? = null) { + return asserter.assertTrue(message ?: "Expected value to be true.", actual) } +/** Asserts that the given [block] returns `false`. */ +public fun assertFalse(message: String? = null, block: () -> Boolean): Unit = assertFalse(block(), message) + /** Asserts that the expression is `false` with an optional [message]. */ -public fun assertFalse(actual: Boolean, message: String = "") { - return assertEquals(false, actual, message) +public fun assertFalse(actual: Boolean, message: String? = null) { + return asserter.assertTrue(message ?: "Expected value to be false.", !actual) } /** Asserts that the [expected] value is equal to the [actual] value, with an optional [message]. */ -public fun assertEquals(expected: Any?, actual: Any?, message: String = "") { +public fun assertEquals(expected: Any?, actual: Any?, message: String? = null) { asserter.assertEquals(message, expected, actual) } /** Asserts that the [actual] value is not equal to the illegal value, with an optional [message]. */ -public fun assertNotEquals(illegal: Any?, actual: Any?, message: String = "") { +public fun assertNotEquals(illegal: Any?, actual: Any?, message: String? = null) { asserter.assertNotEquals(message, illegal, actual) } /** Asserts that the [actual] value is not `null`, with an optional [message]. */ -public fun assertNotNull(actual: T?, message: String = ""): T { +public fun assertNotNull(actual: T?, message: String? = null): T { asserter.assertNotNull(message, actual) return actual!! } /** Asserts that the [actual] value is not `null`, with an optional [message] and a function [block] to process the not-null value. */ -public inline fun assertNotNull(actual: T?, message: String = "", block: (T) -> R) { +public fun assertNotNull(actual: T?, message: String? = null, block: (T) -> R) { asserter.assertNotNull(message, actual) if (actual != null) { block(actual) @@ -55,28 +53,30 @@ public inline fun assertNotNull(actual: T?, message: String = "", b } /** Asserts that the [actual] value is `null`, with an optional [message]. */ -public fun assertNull(actual: Any?, message: String = "") { +public fun assertNull(actual: Any?, message: String? = null) { asserter.assertNull(message, actual) } /** Marks a test as having failed if this point in the execution path is reached, with an optional [message]. */ -public fun fail(message: String = "") { +public fun fail(message: String? = null) { asserter.fail(message) } /** Asserts that given function [block] returns the given [expected] value. */ public fun expect(expected: T, block: () -> T) { - expect(expected, "expected " + expected, block) + assertEquals(expected, block()) } /** Asserts that given function [block] returns the given [expected] value and use the given [message] if it fails. */ -public fun expect(expected: T, message: String, block: () -> T) { - val actual = block() - assertEquals(expected, actual, message) +public fun expect(expected: T, message: String?, block: () -> T) { + assertEquals(expected, block(), message) } +@deprecated("Use assertFails instead.", ReplaceWith("assertFails(block)")) +public fun fails(block: () -> Unit): Throwable? = assertFails(block) + /** Asserts that given function [block] fails by throwing an exception. */ -public fun fails(block: () -> Unit): Throwable? { +public fun assertFails(block: () -> Unit): Throwable? { var thrown: Throwable? = null try { block() @@ -93,15 +93,31 @@ public fun fails(block: () -> Unit): Throwable? { * or TestNG assertion facilities. */ public interface Asserter { + /** + * Fails the current test with the specified message. + * + * @param message the message to report. + */ + public fun fail(message: String?): Unit + + /** + * Asserts that the specified value is `true`. + * + * @param lazyMessage the function to return a message to report if the assertion fails. + */ + public fun assertTrue(lazyMessage: () -> String?, actual: Boolean): Unit { + if (!actual) { + fail(lazyMessage()) + } + } + /** * Asserts that the specified value is `true`. * * @param message the message to report if the assertion fails. */ - public fun assertTrue(message: String, actual: Boolean): Unit { - if (!actual) { - fail(message) - } + public fun assertTrue(message: String?, actual: Boolean): Unit { + assertTrue({message}, actual) } /** @@ -109,24 +125,17 @@ public interface Asserter { * * @param message the message to report if the assertion fails. */ - public fun assertEquals(message: String, expected: Any?, actual: Any?): Unit + public fun assertEquals(message: String?, expected: Any?, actual: Any?): Unit { + assertTrue({ (message?.let { "$it. " } ?: "") + "Expected <$expected>, actual <$actual>." }, actual == expected) + } /** * Asserts that the specified values are not equal. * * @param message the message to report if the assertion fails. */ - public fun assertNotEquals(message: String, illegal: Any?, actual: Any?): Unit - - /** - * Asserts that the specified value is not `null`. - * - * @param message the message to report if the assertion fails. - */ - public fun assertNotNull(message: String, actual: Any?): Unit { - if (actual == null) { - fail(message) - } + public fun assertNotEquals(message: String?, illegal: Any?, actual: Any?): Unit { + assertTrue({ (message?.let { "$it. " } ?: "") + "Illegal value: <$actual>." }, actual != illegal) } /** @@ -134,16 +143,17 @@ public interface Asserter { * * @param message the message to report if the assertion fails. */ - public fun assertNull(message: String, actual: Any?): Unit { - if (actual != null) { - fail(message) - } + public fun assertNull(message: String?, actual: Any?): Unit { + assertTrue({ (message?.let { "$it. " } ?: "") + "Expected value to be null, but was: <$actual>." }, actual == null) } /** - * Fails the current test with the specified message. + * Asserts that the specified value is not `null`. * - * @param message the message to report. + * @param message the message to report if the assertion fails. */ - public fun fail(message: String): Unit + public fun assertNotNull(message: String?, actual: Any?): Unit { + assertTrue({ (message?.let { "$it. " } ?: "") + "Expected value to be not null." }, actual != null) + } + } diff --git a/libraries/stdlib/src/kotlin/test/TestJVM.kt b/libraries/stdlib/src/kotlin/test/TestJVM.kt index 4f88e96c70d..244f183ea96 100644 --- a/libraries/stdlib/src/kotlin/test/TestJVM.kt +++ b/libraries/stdlib/src/kotlin/test/TestJVM.kt @@ -1,21 +1,40 @@ package kotlin.test import java.util.ServiceLoader +import kotlin.reflect.KClass -/** Asserts that a [block] fails with a specific exception being thrown */ -public fun failsWith(exceptionClass: Class, block: ()-> Any): T { +@deprecated("Use assertFailsWith instead.", ReplaceWith("assertFailsWith(exceptionClass, block)")) +public fun failsWith(exceptionClass: Class, block: ()-> Any): T = assertFailsWith(exceptionClass, { block() }) + +/** Asserts that a [block] fails with a specific exception being thrown. */ +public fun assertFailsWith(exceptionClass: Class, block: () -> Unit): T = assertFailsWith(exceptionClass, null, block) + +/** Asserts that a [block] fails with a specific exception being thrown. */ +public fun assertFailsWith(exceptionClass: Class, message: String?, block: () -> Unit): T { try { block() - asserter.fail("Expected an exception to be thrown") - throw IllegalStateException("Should have failed") - } catch (e: T) { + } + catch (e: Throwable) { if (exceptionClass.isInstance(e)) { - return e + return e as T } + asserter.fail((message?.let { "$it. "} ?: "") + "Expected an exception of type $exceptionClass to be thrown, but was $e") throw e } + val msg = message?.let { "$it. " } ?: "" + asserter.fail(msg + "Expected an exception of type $exceptionClass to be thrown, but was completed successfully.") + throw IllegalStateException(msg + "Should have failed.") } +/** Asserts that a [block] fails with a specific exception of type [exceptionClass] being thrown. */ +public fun assertFailsWith(exceptionClass: KClass, message: String? = null, block: () -> Unit): T = assertFailsWith(exceptionClass.java, message, block) + +/** Asserts that a [block] fails with a specific exception of type [T] being thrown. + * Since inline method doesn't allow to trace where it was invoked, it is required to pass a [message] to distinguish this method call from others. + */ +public inline fun assertFailsWith(message: String, @noinline block: () -> Unit): T = assertFailsWith(T::class.java, message, block) + + /** * Comments out a [block] of test code until it is implemented while keeping a link to the code * to implement in your unit test output @@ -51,20 +70,10 @@ public var asserter: Asserter */ private class DefaultAsserter() : Asserter { - public override fun assertEquals(message : String, expected : Any?, actual : Any?) { - if (expected != actual) { - fail("$message. Expected <$expected> actual <$actual>") - } - } - - override fun assertNotEquals(message : String, illegal: Any?, actual : Any?) { - if (illegal == actual) { - fail("$message. Illegal value: <$illegal>") - } - } - - - public override fun fail(message : String) { - throw AssertionError(message) + public override fun fail(message : String?) { + if (message == null) + throw AssertionError() + else + throw AssertionError(message) } } \ No newline at end of file