2013-02-12 2 views
9

Возможно ли получить доступ к имени текущего исполняемого теста из теста ScalaTest? (А как бы я это сделать?)Доступное имя теста ScalaTest из внутреннего теста?

фона:

Я проверяю, что мой доступ к данным объекта в конце концов бросает OverQuotaException, если пользователь, например, создает слишком много страниц. Эти тесты занимают довольно много времени. Чтобы чувствовать себя счастливее, я бы хотел напечатать прогресс в stdout - и, поскольку тестов довольно много, я бы хотел включить тестовое имя в вывод, поэтому я знаю, какой тест в настоящее время выполняется.

(я не нашел, казалось бы, соответствующую функцию здесь: http://www.artima.com/docs-scalatest-2.0.M5/#org.scalatest.FreeSpec)

Пример:

"QuotaCharger can" - { 
    "charge and decline quota consumers" - { 

     "charge a per site IP number (guest user)" in { 
     // ... Here, a guest user post very many comments until it's over quota. 
     // This takes a little while, and there are many similar tests. 

     // ---> Here <--- I'd like to access the string: 
     // "charge a per site IP number (guest user)", 
     // is that possible somehow? 
     } 

ответ

8

Намеренный способ сделать это - переопределить с помощью Fixture и захватить тестовые данные. В этом случае лучше переопределить с помощью fixture в файле fixture.FreeSpec, чтобы вы могли передавать тестовые данные в каждый тест, а не с помощью var. Информация о том, что здесь:

http://www.artima.com/docs-scalatest-2.0.M5/org/scalatest/FreeSpec.html#withFixtureNoArgTest

Когда я увидел ваш вопрос сегодня утром я понял, ScalaTest должен иметь признак, который делает это, так что я просто добавил один. Это будет в версии 2.0.M6, следующей версии релиза, но пока вы можете использовать локальную копию. Вот оно:

import org.scalatest._ 

/** 
* Trait that when mixed into a <code>fixture.Suite</code> passes the 
* <code>TestData</code> passed to <code>withFixture</code> as a fixture into each test. 
* 
* @author Bill Venners 
*/ 
trait TestDataFixture { this: fixture.Suite => 

    /** 
    * The type of the fixture, which is <code>TestData</code>. 
    */ 
    type FixtureParam = TestData 

    /** 
    * Invoke the test function, passing to the the test function to itself, because 
    * in addition to being the test function, it is the <code>TestData</code> for the test. 
    * 
    * <p> 
    * To enable stacking of traits that define <code>withFixture(NoArgTest)</code>, this method does not 
    * invoke the test function directly. Instead, it delegates responsibility for invoking the test function 
    * to <code>withFixture(NoArgTest)</code>. 
    * </p> 
    * 
    * @param test the <code>OneArgTest</code> to invoke, passing in the 
    * <code>TestData</code> fixture 
    */ 
    def withFixture(test: OneArgTest) { 
    withFixture(test.toNoArgTest(test)) 
    } 
} 

Вы бы использовать его как это:

import org.scalatest._ 

class MySpec extends fixture.FreeSpec with TestDataFixture { 
    "this technique" - { 
    "should work" in { td => 
     assert(td.name == "this technique should work") 
    } 
    "should be easy" in { td => 
     assert(td.name == "this technique should be easy") 
    } 
    } 
} 
+0

Я думаю, что я предпочитаю подход 'def currentTestName: String' на самом деле, что вы можете получить доступ из любого места, не передавая никаких параметров (и изменяя сигнатуры функций только для целей отладки). С моей точки зрения, тестовое имя не является частью теста - это только отладочная информация. Но когда он появляется как параметр для теста ('td =>'), то он, кажется, является частью теста. – KajMagnus

+1

Что делать, если ваш тест принимает «реальный» параметр прибора? Тогда либо вам нужно будет принять 2 параметра для каждого теста? '" имя теста "в {case (td, realTestData) => ...}'. Или, возможно, не удастся также пройти тест «realTestData»? Поскольку один и только параметр, переданный в тест, будет тем, который предоставил имя теста (для целей отладки). – KajMagnus

+0

Ну, имейте в виду, что currentTestName работает только в том случае, если тесты выполняются последовательно, что будет истинным, если вы не смешаете ParallelTestExecution. В этом случае вы можете просто установить var в withFixture в обычном FreeSpec. Если тесты выполняются последовательно, подход к шляпе также будет работать и звучит менее навязчиво, если это только для отладки временно. Я предполагал, что это будет навсегда. –

2

Создайте свою собственную черту, скажем RichFreeSpec.

trait RichFreeSpec extends Free { 
    protected final class RichFreeSpecStringWrapper(name: scala.Predef.String) { 
    def in(f: String => scala.Unit) { 
     def f2 = f(name) 
     new WordSpecStringWrapper(string).in(f2) 
    } 
    } 

    protected implicit def convertToRichFreeSpecStringWrapper(n: scala.Predef.String): = { 
    new RichFreeSpecStringWrapper(n) 
    } 
} 

чем просто использовать:

"sth" in { testName => 
    ... 
} 

Конечно, вы можете пойти дальше и осуществить полную иерархию имен.

+0

Спасибо! На самом деле это не сработало: каждый раз, когда «последнее имя теста» в {...} 'запускается,' currentTestName' изменяется на «самое последнее имя теста» и когда фактические тестовые блоки (внутри '{.. ,} '),' currentTestName' всегда то же самое, а именно '' последнее имя теста ''. – KajMagnus

+0

Благодаря вашему ответу я нашел соответствующие классы и мог придумать что-то :-) Поэтому +1, потому что ответ был полезен. (... Я приму свой ответ через 2 дня (некоторый предел)) – KajMagnus

+0

Извините за мою ошибку. Исправлена. – Jakozaur

1

Вот решение. Расширьте этот класс вместо FreeSpec. Лицензия: CC0.

Редактировать: Это не работает с параллельными тестами.

(Разница между этим подходом и другим ответом состоит в том, что 1) здесь есть поле currentTestName, а в другом ответе тестовое имя передается тесту и 2) это тестовое имя включает в себя все тесты названия ветви каскадных + фактическое имя тестируемого, в то время как название теста другого ответа является именно названием теста (без имен теста ветви).)

(Упс, вы должны были бы использовать getOrElse ... вместо моей прекрасной getOrDie.)

/** 
* Adds a field `currentTestName` that you can use inside a FreeSpec test, 
* if you for example have many tests that take rather long, and you wonder 
* which one is currently running. 
*/ 
trait RichFreeSpec extends FreeSpec { 

    private var _currentTestName: Option[String] = None 
    def currentTestName = _currentTestName getOrDie "DwE90RXP2" 

    protected override def runTest(testName: String, args: org.scalatest.Args) { 
    _currentTestName = Some(testName) 
    super.runTest(testName, args) 
    } 
} 
Смежные вопросы