 Okay, hello everyone Welcome to Singapore EPM Vita 6th edition So a little bit of introduction about myself. I am Abhijeet Vaikar. I am a QA engineer And I've been working in the testing domain since six years and seven months now Initially worked with cognizant for a couple of years now. I'm working as a quality engineer in carousel So a little bit about carousel. So carousel is Southeast Asia's largest and fastest growing mobile market places It's a highly rated Android and iOS phone which makes selling as easy as clicking a picture and buying as easy as chatting So has anyone over here used carousel until now? Okay, so for those who have not used just try it out once and in case if you find any If you have any concerns or issues, you know who to talk talk to So what are we here for? So we are here for why we should avoid abusing static methods in automation frameworks what we can do about it and How we can use dependency injection frameworks to simplify our automation scripts So let's first start with the why? So a few weeks back our very own Sam had posted Post on LinkedIn. I'm not sure if everyone Saw it But it was basically about his challenges that he had faced while creating test automation frameworks and most specifically about using static methods and variables So there were a lot of different comments and responses that Many people gave on this post and it was quite an insightful discussion so Any of this code does this look familiar like every anyone who has actually gone into the process of creating test automation frameworks using languages like Java or C sharp.net Does any of this code look familiar to you probably the kind of things that you implemented very in the very beginning of your career Like for example screenshot you till dot capture screenshot or APM you till dot scroll down user service dot get user or Does this any of this look familiar? Particularly the last one which is private static Android driver development driver So what's wrong with that? I mean it's okay, right? I mean if you even if you declare anything any variable a static or if you call static methods so let us look at some of the issues that they come across while Dealing with static methods and variables So one of the most critical issues that we come across in test automation frameworks is one of the issues because all starting objects are shared between multiple threads and The kind of issues that you will come come across due to the race conditions caused by them You can not imagine the kind of issues that are there So for example, let's say you have created two different variables for example private static web driver driver private static hash map test results map and When you run your tests concurrently in multiple threads Imagine thread one using the same variable thread two and thread three using the same variable all of them either entering some value or obtaining some value out of it so Anything can happen thread one can probably get a value which is meant to be read by thread two The next issue is about design So I had come across a lot of different people implementing Automation scripts in this manner where they are actually calling some static methods on the classes Instead of instantiating or you know using pure object oriented concepts so Something else something else like login page dot go to login page dot login as so these are all static methods being called on classes so Technically and conceptually it's not really an efficient way of writing scripts Another issue is about mutable state So if you create any static objects open to change so you have created a static object and You are setting a value to it and then someone else comes and writes Code which changes its value. So it does not fulfill the purpose of making it static, right? So this is also one of the issues that you can come across So for example, you can see over here. There is a Login endpoint string, which is public static. That's what you have already been But someone else in some other class Tries to set the property. It can be just a mistake done by the engineer, but then whenever the test gets executed for the API that will get called will not be the API login, but it'll be API log out So what can we do about it? so Whenever whenever we whenever we get some doubts like these or when we ask these kind of questions to our colleague Martin Schneider, he basically says make the framework smart so that test code can be short and simple The test code should basically be so concise that it doesn't matter which language is used to run it and That's that's Martin who is trying to come out of the Kochi tunnel in Vietnam. So When it comes to concurrency, what can we do about it? So whenever you are if you want to declare your driver or driver object as static and you are running your tests Parallely using concurrency Then make sure that using thread local along with it. So when you declare your driver object as thread local It will make sure that the multiple threads get different copies of the same static variable Another option that we can think of if you don't want to use thread local then use dependency injection with non-static object So basically use dependency injection with a real instance of a driver and not a static instance as far as design is concerned you can solve these issues by using object-oriented programming concepts, so Considering the example that I showed to you in previous slide where Every script was called every page object was called with a static method. What you can do on the contrary is Create instances of those page objects and call the instance methods on them You can also incorporate something something as simple as method chain Which will make it much more easier for anyone to read the script Where in every method will return the same instance of the class which will help you to compose your script in such a way that it is easy to read and If you want to get if you want to go few steps further you can also enhance these scripts using dependency injection What about mutable state? So as I mentioned before mutable state if you are creating mutable static objects They can always be overwritten with other values. So to avoid this always make sure that any Constance or any mutable static objects that you are creating should be declared along should have finally declared in it So I mentioned dependency injection a couple of times in the previous slide. So what exactly is a dependency injection? Conceptually it it really seems to be a very complicated subject and The most confusing part of your is because of the word injection that what are we injecting into it? So it basically means nothing but Giving the dependency to anyone who needs it So let's look at the basic examples over here What will be the kind of? Example where you are not performing any dependency injection. So consider the class employee which needs an address so employee has a member variable address and Employee itself creates an instance of the address variable so this kind of creates a very tight coupling because You cannot change if you want to pass any any other address you cannot change it You will always have to go inside the employee class and change the implementation of address On the contrary when it comes to dependency injection You create an instance of employee And you also create an instance of address and you pass the instance of address to employee. So basically employee needs So your code is basically passing the address to the employee class as a dependency. So it's basically dependency injection So if you observe over here, it has been done in multiple ways one is using constructor. So I'm passing The instance of address via constructor of employee. The other approach is By calling a setter method So employee.set address new address so I'm sure most of you must be knowing about page object design pattern, right? So it's why it's quite common for All of us to Whenever we start implementing page object design pattern very initially in our stages of Implementing automation framework. What we tend to do is that we tend to Pass the driver instance via the constructor of the page object So login page login page equal to new login page pass the driver and then we basically keep passing the beton to every one So that is also one way of dependency injection itself, which we have been doing till now Another one another example that we quite often Use but probably we not we not really think about whether it is dependency injection dependency injection or not is using test engines Before methods or any other methods, right? So over here This is an example of test engine before method where you can pass a reference of it as context And I test context is basically an object which contains information about the test that you pick up from the test and your example So over here you are actually not passing the value or the object of it as context manually to this method It is being done automatically by test engine. So that is basically dependency injection so the examples that you saw earlier where Dependency injection, which were done manually like you actually wrote code you created a created a new instance of the dependencies Dependency classes and then passed it on to the classes which required the dependency all of this was being done manually What if you actually tell a third-party framework to handle all of this behind the scenes? This is where dependency injection frameworks come into picture So what can a dependency injection framework do so you can use a dependency dependency injection framework instead of managing dependencies manually When it comes to Java, there are a couple of popular dependency injection frameworks like spring Google choose pico container and daddler These frameworks use inversion of control container in which all the dependencies are registered initialized and managed So the version of control is basically a concept where as I mentioned The dependency that is required by any class the class does not really bother about Creating its own the creating its own dependency. It is being handed over to the class by someone else So this is inversion of control There is a very famous analogy which is called as the Hollywood principle where What happened was anyone who used to come to auditions for getting Getting a role in a film used to go to those people and the people would say don't call us We call you so once the dependencies are instantiated the container injects them using approaches like Constructor injection setter method inject injection and field injection. So in our previous examples, you saw Dependency is getting injected either via the constructor or using setter methods, but The dependency injection frameworks can also perform injection directly at the field level What are the benefits of using dependency injection? As a basic principle the basic the benefits are single responsibility principle So as you saw earlier Employee class does not really need to know how to create the instance of address So address class and employee class are completely loosely coupled That is single responsibility principle employee class is meant to do what it's meant to do it will not bother about address clean readable code and Isolated components which become easy for testing as dependencies are loosely coupled. So if you want to test Something related to address then you can simply pass another instance of address and it will You can basically test it easily Now how can we use dependency injection frameworks to simplify automation scripts? So the example that we are going to see is using spring dependency injection framework Spring is a popular Dependent not only a dependency injection framework, but it's a huge application development ecosystem dependency injection and its IOC container is just one small part of it So we'll look at the IOC and dependency injection part of the spring framework So how does spring perform DI? so any Java classes That you want spring to take care of basically take care of in the sense create its instances Manage the life cycle of the objects Any classes that you want spring to handle you need to configure and tell spring Okay, these are the classes that you should automatically take care of I'm not going to create new instances for them So spring how does spring come to know which classes should be handled using dependency injection? It takes all the information from a configuration file So configuration file can either be a Java class or it can be an XML file but as compared to XML file Java class configuration is quite easier to maintain and Is much more popular these days? So and so all the information regarding which dependencies should be instantiated once spring knows then it creates those creates the instances of those dependencies and then makes them available for use So I'll just go through some commonly used annotations in spring which help us to perform DI one is accurate component At the right component annotation if you mark any Java class with accurate component annotation It becomes a bean or a component which will be handled by spring So spring is able to identify any class Java class as a class that needs to be taken care of behind the scenes with the help of this component With the help of this annotation another one is configuration so the configuration that I told you about It can either be an XML or Java class So if you if you annotate any Java class with at the rate configuration Annotation then it will act as a configuration for spring At the rate profile, so it is used for conditional loading of classes based on use cases. So Considering the use case for automation scripts. We often have different Variables or parameters like you want to run these scripts on Production or you want to run these scripts on staging You want to run the scripts on Android platform instead of iOS platform. So you can load some objects based on Specifying the profile so you can tell okay. I want to I want to load the objects with profile Android so all the objects related to the Android profile will be loaded into the memory At the rate auto wired so this is quite a good Spring annotation so any field or setter method that you annotate with the annotation at the rate auto wired the dependency on the Field or the setter method is automatically injected by spring and The last one is been so I mentioned about configuration, right? So any configuration class that spring reads the dependency data from any method inside that configuration class if you want it to be initializing a Bean or a dependency you can annotate that method with at the rate bean So enough of theoretical knowledge and let's get on to Implementation so this is an example of a test script which does not use any dependency injection at all So you as you can see we have created Instances of all different page objects new welcome page. We are passing driver to the constructor and Calling the page object methods on them So what are two two things that you can observe over here? Driver is a dependency for page objects And another thing is page objects are also a dependency for the test class So this is basically a test class inside this test class is a test method so Imagine a situation where you have multiple test methods and you are dealing with the page objects. So you are creating Instances of page objects in every single test method So that that means that these page objects are also a dependency to the test class also one more point is Is it really necessary to create new instance of page object every time? So you have multiple test methods and each test method you are creating welcome page equal to new welcome page and so on So is it really necessary? So let us look at one of the page object classes, which is welcome page So welcome page as you saw we are passing the driver instance to welcome page So welcome page also has its own member variable Which is a web driver variable. We are passing the driver instance driver instance to the constructor So inside the constructor you are calling super driver and this is our driver equal to driver This is a very common pattern that most of us follow when creating page objects Now, how can we actually enhance these scripts? So the first thing that we can do is we first need to create a configuration file for spring To tell spring that okay. I want to manage these dependencies. I want you to manage this dependency automatically So we have created a class called spring context. It's just a plain class. It's nothing complicated What to do is now in order to tell spring that this is a configuration class you will annotate it with the annotation at the configuration Remember the connotations that I spoke about earlier Now inside this configuration class You can create different beam methods. What are As you can see over here they are methods which will basically return to you instances of any dependencies that you want in any of the classes So earlier we saw that we are actually passing driver instance to every page object via the constructor Right. What if we want to eliminate this need? I don't really need to pass driver instance every time around, right? So what we can do is we can create a method called as get by driver Annotate it with the annotation at the rate D. So that spring knows that this needs to be injected somewhere Inside this is the code where you are Identifying whether you want to create an instance for Chrome driver, Android driver or iOS driver and return return the driver Now let us look back at the welcome page in this case now what you can do is You already have the member variable web driver driver simply annotate it with the annotation auto wired So as I mentioned whenever you annotate a variable Or a setup method or a constructor with auto wired spring injects the instance Of the dependency behind this means you don't really need to worry about anything. So in this case When and when a new instance of welcome pages created Spring knows that okay. I need to or I need to inject the dependency of driver because it's auto wired So it will inject it now now the second case is basically about Page objects as I also mentioned that page objects are a dependency to the test class And I don't really want to create a new instance of page objects every time I create a new test method So how can we enhance that as well? So what you can do is you can annotate the page object class with an annotation called as component Once you annotate this class with component annotation The result Is basically you will be able to write scripts like these So compare the previous example with this example You are not new instance of page objects everywhere Because what you have done is now you have created auto wired variables for all the page objects in your test class So whenever you execute your tests Spring will find that. Okay. These are the variables. These are the page object variables that need to be injected spring will inject the values spring will first create an instance of the page object variables and then Inject the values into the variables So it basically leads us to writing a simple script like this Nothing complicated just using the reference of the reference of the page object and calling the method on it So do you do you feel that the previous script The current script is actually much more better and readable as compared to the previous script Yeah Another example which can Where in spring can actually be very useful is using the profile annotation So let's say you are Maintaining different page objects for the platform So you have you have you're writing common scripts for multiple platforms. One is web. One is android and one is ios right, so You can adopt this kind of This kind of inheritance Where you create a base Create an abstract for the page that you want to deal with and subclass then with platform dependent page objects So any functionality or any operations that you want to include for that specific platform Will be in those page objects only Anything which is common which will anything which will which is common will be over here So in such situation If we want to tell spring or if you want to use dependency injection wherein My reference variable is welcome page But i won't spring to automatically identify that whenever i want to whenever i run scripts for android It should not load Or it should not create an instance for ios welcome page, but it should do it for android welcome page You can do that with the help of adgrade profile annotation so Profile is part of the spring annotations and you just need to Basically provide the the profile that you want to load. So in this case platform dot android is basically they can enum where profile will when where if you specify something like spring dot profiles dot active This is a standard You can call it a parameter where Whenever you start your tests either from the either from the command line Or you can set this Variable in as a system property or environment property And you can assign the value of the profile Either based on your custom custom requirement like in this case. It's a profile is basically the platform So you'll assign it the value as android or ios and based upon this way The platform dependent page object so all of this sounds really good So is there any real word implementation of such framework? So we Yes, we have a framework like this which has been Getting the really good contribution and it has been started by our our modern snider So you can just check it out So all of this I have been talking all of this about this Very specific to java, but what about other programming languages? So if you want to if you want to use dependency injection in your test automation frameworks as per your programming language I have considered like the major ones which are being used by the test automation community So you can use like dependency injector and spring python for python For ruby you have a syngect and dry container For c sharp you have spring dot net castle windsurf unity and auto fact And for javascript water js or inversify js di ninja This is not an exhaustive list. You can find many more on the internet Thank you Any questions you can pass it Component scan is useful when you want to test spring to automatically Go through a set of packages Where in you can have classes which are annotated with the component Annotation, so if you are using if you are using classes annotated with the component Annotation then you need to tell Spring configuration that okay. These are the these are the this is the package inside which the classes are annotated with the component Annotation because if you do not specify then How is spring going to identify where should I search the components from? So if you're using components, then yes, you need to use component scan As far as I know So as I mentioned if you are using if you're using web driver, right so When you are executing your tests Uh, concurrently like multiple if you're executing the uh tests in multiple threads and if your Driver instance is not thread safe Then many threads are going to actually access the same instance of the driver Sorry Dependency injection has really nothing to do with Thread safety or concurrency dependency injection basically Tells you or lets you handle how objects are getting created or and managed Thread safety is a completely different Concern to deal with so if you're talking about how I can actually maintain concurrency Using spring and not using thread local as well. Then spring has this concept of scope So scope is basically How an object gets created so by default whenever you create A beam beam is basically nothing but an instance of an object in spring when spring creates an instance of an object the default scope is singleton But if you want to create multiple instances of a beam then you can provide the scope as prototype But over here now in case of web driver We do not want multiple instances of web driver to create get created, right? so What you can do is there is another scope called as thread thread scope simple thread scope Which using using which you can actually create It is something very similar to thread local also. So what spring will do is it will Internally it will use thread local. So even if you have multiple threads using the driver instance It is not going to actually cause any concurrency concurrency issues Yeah Thank you