Search code examples
scalasingletonimplicitscalatest

Is there an idiomatic way to convert a Class to an Object when the class relies on an implicit?


I'm new to Scala.

I have a series of test classes that perform UI tests, and a series of classes that contain reusable helper methods.

Example Test 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
}

Example Helper Class:

class MyCoolPage(implicit driver:WebDriver) {
    def clickElement1(){
     //relies on driver
    }
    def assertElement2Enabled(){
     //relies on driver
    }
}

Now, none of the helper classes actually have mutable state. This makes me want to convert them from classes to objects.

However, the only way I can figure out how to do this is to add an implicit WebDriver argument to every method. That works, but it's ugly. Are there any more concise ways to achieve what I want here? Alternatively, is there a more idiomatic way to organize this Test Class / Helper Method relationship entirely?


Solution

  • I'd argue, there is no idiomatic way to convert the classes to objects, as you are asking. And here is my point of view on why:

    You declared an attribute driver in MyCoolClass, you are using in the methods. Therefore your class actually has state. The WebDriver is state injected into MyCoolPage. Depending on the implementation of the injected WebDriver, the way method calls are handled may vary.

    To overcome this, you'd need to give the WebDriver as implicit argument to each of your methods, as you found out by yourself. However, this would allow to externally replace the driver during runtime. This would violate the Open-Closed-Principle, which I'd argue is even less idiomatic than using your class construct.

    If you encounter this problem again in the future, you might try to write the code without the use of implicit. If it still seems like an appropriate way to change class to object, you are probably good to go.