ScalaTest: Проблемы с реинициализацией Объекта Singleton

Я тестирую синтаксический анализатор, который я записал в использовании Scala ScalaTest. Синтаксический анализатор обрабатывает один файл за один раз, и он имеет одноэлементный объект как следующее:

class Parser{...}
object Resolver {...}

Тестовый сценарий, который я записал, несколько похож на это

   describe("Syntax:") {
    val dir = new File("tests\\syntax");
    val files = dir.listFiles.filter(
                    f => """.*\.chalice$""".r.findFirstIn(f.getName).isDefined);

    for(inputFile <- files) {
      val parser = new Parser();
      val c = Resolver.getClass.getConstructor();
      c.setAccessible(true);
      c.newInstance();

      val iserror = errortest(inputFile)
      val result = invokeparser(parser,inputFile.getAbsolutePath) //local method
      it(inputFile.getName + (if (iserror)" ERR" else " NOERR") ){
      if (!iserror) result should be (ResolverSuccess()) 
        else if(result.isInstanceOf[ResolverError]) assert(true)
      }
    }
  }

Теперь при каждом повторении побочные эффекты предыдущих повторений в одиночном элементе возражают, что Сопоставитель не очищен.

Там какой-либо путь состоит в том, чтобы указать к scalatest модулю, чтобы повторно инициализировать одноэлементные объекты?

Обновление: Используя предложение Daniel, я обновил код, также добавили больше деталей.

Обновление: По-видимому, это - Синтаксический анализатор, который делает что-то подозрительное. При последующих вызовах это не отбрасывает предыдущий AST.странно. так как это вне темы, я вырыл бы больше и вероятно использовал бы отдельный поток для обсуждения, благодарен за то, что все отвечают

Заключительное Обновление: проблема была с одноэлементным объектом кроме Сопоставителя, это было в некотором другом файле, таким образом, я так или иначе пропустил его. Я смог решить этот ответ Daniel Spiewak использования. Это - грязный способ сделать вещи, но также единственная вещь, учитывая мои обстоятельства и также, учитывая факт я пишу тестовый код, который не входит в производственное использование.

9
задан thequark 4 August 2010 в 14:01
поделиться

2 ответа

Согласно спецификации языка, нет, нет возможности воссоздать одноэлементные объекты. Однако возможно рефлексивно вызвать конструктор синглтона, который перезаписывает внутреннее поле MODULE $ , которое содержит фактическое значение синглтона:

object Test

Test.hashCode    // => e.g. 779942019

val c = Test.getClass.getConstructor()
c.setAccessible(true)
c.newInstance()

Test.hashCode    // => e.g. 1806030550

Теперь, когда я поделился злая тайна с вами, позвольте мне предостеречь вас никогда, никогда не делать этого. Я бы очень и очень постарался скорректировать код, вместо того, чтобы разыгрывать такие хитрые уловки, как этот. Однако, если все обстоит так, как вы говорите, и у вас действительно нет другого выхода, это хоть что-то.

7
ответ дан 3 November 2019 в 00:57
поделиться

В ScalaTest есть несколько способов, позволяющих повторно инициализировать объекты между тестами. Однако на этот конкретный вопрос сложно ответить, не зная больше. Главный вопрос будет заключаться в том, что нужно для повторной инициализации одноэлементного объекта? Если одноэлементный объект не может быть повторно инициализирован без создания нового одноэлементного объекта, вам необходимо убедиться, что каждый тест загружает одноэлементный объект заново, что потребует использования пользовательских загрузчиков классов. Однако мне трудно поверить, что кто-то может спроектировать что-то таким образом. Можете ли вы добавить в свой вопрос более подробную информацию? Я посмотрю еще раз позже и посмотрю, сделают ли ответ более очевидным из-за дополнительных деталей.

ScalaTest имеет путь выполнения, который загружает классы заново при каждом запуске, но не путь тестирования. Так что вам придется кататься самостоятельно. Настоящая проблема здесь в том, что кто-то спроектировал это так, что это нелегко проверить. Я бы посмотрел на загрузку Resolver и Parser с URLClassLoader внутри каждого теста. Таким образом, вы будете получать новый резолвер на каждый тест.

Вам нужно убрать Parser & Resolver с пути к классам и с пути выполнения. Поместите их в собственный каталог. Затем создайте URLClassLoader для каждого теста, который указывает на этот каталог. Затем вызовите findClass ("Parser") в этом загрузчике классов, чтобы получить его.Я предполагаю, что Parser относится к Resolver, и в этом случае JVM вернется к загрузчику классов, который загрузил Parser, чтобы получить Resolver, который является вашим URLClassLoader. Сделайте newInstance в Parser, чтобы получить экземпляр. Это должно решить вашу проблему, потому что вы получите новый одноэлементный объект Resolver для каждого теста.

4
ответ дан 3 November 2019 в 00:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: