2010-08-04 3 views
9

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

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) 
     } 
    } 
    } 

Теперь на каждой итерации побочных эффектов предыдущих итерации внутри одиночного объекта Resolver не очищаются.

Можно ли указать модуль scalatest для повторной инициализации одиночных объектов?

Обновление: Используя предложение Даниэля, я обновил код, а также добавил более подробную информацию.

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

Final Update: Проблема была с одноплодной объект, кроме Resolver, он был в каком-то другом файле поэтому я как-то пропустил это. Я смог решить это, используя ответ Дэниела Сплекака. Это грязный способ делать что-то, но это тоже единственное, учитывая мои обстоятельства, а также учитывая тот факт, что я пишу тестовый код, который не собирается использоваться в производстве.

+0

Есть ли способ очистки внутри 'R', или вы ожидаете его воссоздания? –

+0

В R отсутствует метод очистки, и я не могу изменить код. Можете ли вы воссоздать одноэлементные объекты в Scala? – thequark

+0

Нет. Они строго одиночные. Инициализируется по требованию (как определено загрузкой класса JVM), а затем вечно. Разумеется, они могут иметь изменяемое внутреннее состояние, как и для любых классов Scala. –

ответ

7

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

object Test 

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

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

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

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

+1

Повторная инициализация объекта singleton таким образом работает, но моя проблема по-прежнему сохраняется. Я не знаю, как это сделать. В принципе, если я тестирую каждый входной файл отдельно, он работает нормально, но если я тестирую их вместе, я получаю ошибку. Если я изменил порядок, я также получу ошибку (с сообщениями об ошибках, связанными с предыдущим тестовым случаем!). Я подозревал, что это может быть причиной, потому что объект singleton имеет побочные эффекты от предыдущих итераций. – thequark

+0

Пробовал, получил это ... java.lang.NoSuchMethodException: com.whatever.SingletonObject $. () – jm0

+0

Мне пришлось изменить приведенный выше пример @ daniel-spiewak на 'val c = Test.getClass.getDeclaredConstructor()' –

4

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

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

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

+0

Создание нового Parser не переинициализирует объект singleton и создание объекта парсера внутри цикла , (проверьте обновленный код) код был сделан, чтобы принять один входной файл в одной трассировке выполнения. – thequark

Смежные вопросы