我是Scala的新手。
我有一系列执行UI测试的测试类,以及一系列包含可重用的辅助方法的类。
示例测试类:
class MyCoolTestClass extends FreeSpec {
//Note: This driver needs to be configurable by the test in some way.
implicit val driver:WebDriver = new ChromeDriver()
val myCoolPage = new MyCoolPage
//Tests below rely on myCoolPage methods
}
示例助手类:
class MyCoolPage(implicit driver:WebDriver) {
def clickElement1(){
//relies on driver
}
def assertElement2Enabled(){
//relies on driver
}
}
现在,所有帮助程序类实际上都不具有可变状态。这使我想将它们从class
转换为object
。
但是,我唯一能弄清楚该怎么做的方法是在每个方法中添加一个implicit WebDriver
参数。可以,但是很难看。还有其他更简洁的方法可以实现我想要的功能吗?或者,是否有一种更惯用的方式来完全组织这种“测试类/帮助方法”关系?
答案 0 :(得分:2)
您可以将帮助类更改为对象,并仍然为成员方法提供implicit
值。
object MyCoolPage {
private val driver :WebDriver = implicitly[WebDriver]
def clickElement1() = ??? //relies on driver
def assertElement2Enabled() = ??? //relies on driver
}
但是随后implicit
声明必须移出测试类。我想到了两种可能性:WebDriver
对象...
object WebDriver {
implicit val wd :WebDriver = new ChromeDriver()
...
...或专用对象中。
object MyCoolPage {
import MyTestImplicits._
private val driver :WebDriver = implicitly[WebDriver]
...
总而言之,我不认为这值得付出努力。
答案 1 :(得分:1)
考虑使用这样的抽象隐式驱动程序字段将MyCoolPage
变成特征
trait MyCoolPage {
implicit val driver: WebDriver
def clickElement1() = {
//relies on driver
}
def assertElement2Enabled(){
//relies on driver
}
}
然后将MyCoolTestClass
扩展MyCoolPage
并使用自定义配置的驱动程序覆盖driver
字段,如下所示
class MyCoolTestClass extends FreeSpec with MyCoolPage {
override implicit val driver: WebDriver = new ChromeDriver()
//Tests below rely on myCoolPage methods
}
现在MyCoolTestClass
可以访问MyCoolPage
中的每个方法,并且这些方法不需要隐式驱动程序参数。
答案 2 :(得分:1)
我认为,没有惯用的方法,可以按照您的要求将class
转换为object
。这是我对原因的看法:
您在driver
中声明了一个属性MyCoolClass
,您正在这些方法中使用它。因此,您的class
实际上具有状态。 WebDriver
是state injected到MyCoolPage
中。根据注入的WebDriver
的实现,方法调用的处理方式可能会有所不同。
要克服这一点,您需要将WebDriver
作为每个方法的隐式参数,这是您自己发现的。但是,这将允许在运行时从外部替换驱动程序。这会违反Open-Closed-Principle,我认为它甚至比使用您的class
构造还要惯用。
如果以后再次遇到此问题,则可以尝试在不使用implicit
的情况下编写代码。如果将class
更改为object
似乎仍然是一种适当的方法,那么您可能会很高兴。
答案 3 :(得分:0)
现在,所有帮助程序类实际上都不具有可变状态。这使我想将它们从
class
转换为object
。
但是他们确实有状态。是的,它是不可变的,但是大多数案例类的状态Option
,List
也是如此……它们都不应该转换为object
。我认为没有一种解决方案真的比您开始使用的解决方案更好。
但是,这里有一个选择:将帮助器对象嵌套在超类中:
abstract class AbstractTestClass extends FreeSpec {
// may optionally be implicit or non-abstract
val driver: WebDriver
object MyCoolPage {
def clickElement1(){
//relies on driver
}
def assertElement2Enabled(){
//relies on driver
}
}
object MyCoolPage2 ...
}
class MyCoolTestClass extends AbstractTestClass {
override val driver: WebDriver = new ChromeDriver()
// can use MyCoolPage methods
}
请注意,object
的加载是延迟的,因此如果MyCoolTestClass
不使用MyCoolPage2
,则不会为此付费。折衷是所有帮助程序类都必须在一个文件中定义。