当 class 依赖隐式时,是否有一种惯用的方法将 Class 转换为对象?
Is there an idiomatic way to convert a Class to an Object when the class relies on an implicit?
我是 Scala 新手。
我有一系列执行 UI 测试的测试 类,以及一系列包含可重用辅助方法的 类。
示例测试Class:
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:
class MyCoolPage(implicit driver:WebDriver) {
def clickElement1(){
//relies on driver
}
def assertElement2Enabled(){
//relies on driver
}
}
现在,助手 类 的 none 实际上具有可变状态。这让我想将它们从 class
es 转换为 object
s.
但是,我能弄清楚如何执行此操作的唯一方法是向每个方法添加一个 implicit WebDriver
参数。那行得通,但是很难看。有没有更简洁的方法来实现我在这里想要的?或者,是否有更惯用的方式来完全组织此测试 Class / Helper Method 关系?
考虑将 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
中的每个方法,并且这些方法不需要隐式驱动程序参数。
您可以将您的帮助 classes 更改为对象并仍然向成员方法提供 implicit
值。
object MyCoolPage {
private val driver :WebDriver = implicitly[WebDriver]
def clickElement1() = ??? //relies on driver
def assertElement2Enabled() = ??? //relies on driver
}
但是 implicit
声明必须移出测试 class。我想到了两种可能性:WebDriver
对象...
object WebDriver {
implicit val wd :WebDriver = new ChromeDriver()
...
...或在专用对象中。
object MyCoolPage {
import MyTestImplicits._
private val driver :WebDriver = implicitly[WebDriver]
...
总而言之,我不认为这样做是值得的。
Now, none of the helper classes actually have mutable state. This makes me want to convert them from class
es to object
s.
但他们确实有状态。是的,它是不可变的,但大多数情况下 类、Option
s、List
s 的状态也是如此......其中 None 应该转换为 object
s。我认为没有比您开始时更好的解决方案了。
但是,这里有一个选项:将辅助对象嵌套在超类中:
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
,则不会为此付费。权衡是所有助手 类 必须在单个文件中定义。
我认为,没有惯用的方法 可以将 class
es 转换为 object
s,如您所问。这是我对原因的看法:
您在 MyCoolClass
中声明了一个属性 driver
,您正在方法中使用。因此你的 class
实际上有状态。 WebDriver
是 state injected 变成 MyCoolPage
。根据注入的实现 WebDriver
,处理方法调用的方式可能会有所不同。
为了克服这个问题,您需要将 WebDriver
作为每个方法的隐式参数,正如您自己发现的那样。但是,这将允许在运行时从外部替换驱动程序。这将违反 Open-Closed-Principle,我认为 比使用您的 class
构造更不惯用。
如果以后再遇到这个问题,不妨尝试不使用implicit
来写代码。如果将 class
更改为 object
仍然是一种合适的方法,那么您可能就可以开始了。
我是 Scala 新手。
我有一系列执行 UI 测试的测试 类,以及一系列包含可重用辅助方法的 类。
示例测试Class:
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:
class MyCoolPage(implicit driver:WebDriver) {
def clickElement1(){
//relies on driver
}
def assertElement2Enabled(){
//relies on driver
}
}
现在,助手 类 的 none 实际上具有可变状态。这让我想将它们从 class
es 转换为 object
s.
但是,我能弄清楚如何执行此操作的唯一方法是向每个方法添加一个 implicit WebDriver
参数。那行得通,但是很难看。有没有更简洁的方法来实现我在这里想要的?或者,是否有更惯用的方式来完全组织此测试 Class / Helper Method 关系?
考虑将 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
中的每个方法,并且这些方法不需要隐式驱动程序参数。
您可以将您的帮助 classes 更改为对象并仍然向成员方法提供 implicit
值。
object MyCoolPage {
private val driver :WebDriver = implicitly[WebDriver]
def clickElement1() = ??? //relies on driver
def assertElement2Enabled() = ??? //relies on driver
}
但是 implicit
声明必须移出测试 class。我想到了两种可能性:WebDriver
对象...
object WebDriver {
implicit val wd :WebDriver = new ChromeDriver()
...
...或在专用对象中。
object MyCoolPage {
import MyTestImplicits._
private val driver :WebDriver = implicitly[WebDriver]
...
总而言之,我不认为这样做是值得的。
Now, none of the helper classes actually have mutable state. This makes me want to convert them from
class
es toobject
s.
但他们确实有状态。是的,它是不可变的,但大多数情况下 类、Option
s、List
s 的状态也是如此......其中 None 应该转换为 object
s。我认为没有比您开始时更好的解决方案了。
但是,这里有一个选项:将辅助对象嵌套在超类中:
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
,则不会为此付费。权衡是所有助手 类 必须在单个文件中定义。
我认为,没有惯用的方法 可以将 class
es 转换为 object
s,如您所问。这是我对原因的看法:
您在 MyCoolClass
中声明了一个属性 driver
,您正在方法中使用。因此你的 class
实际上有状态。 WebDriver
是 state injected 变成 MyCoolPage
。根据注入的实现 WebDriver
,处理方法调用的方式可能会有所不同。
为了克服这个问题,您需要将 WebDriver
作为每个方法的隐式参数,正如您自己发现的那样。但是,这将允许在运行时从外部替换驱动程序。这将违反 Open-Closed-Principle,我认为 比使用您的 class
构造更不惯用。
如果以后再遇到这个问题,不妨尝试不使用implicit
来写代码。如果将 class
更改为 object
仍然是一种合适的方法,那么您可能就可以开始了。