0

I recently switch from C# to Java and not able to solve this problem. I am automation UI using selenium. I like to build a model for a list of elements on a page, retrieve property and then work with these properties. In the example bellow, I am searching on amazon.com and getting a list of results. I have SearchResultsModel class which represents every item returned, public List<SearchResultModel> GetAllResults(bool title = false;bool isPrime = false;bool price = false) method which retrieves data from UI and place it my model, it has default parameters which allows me to manipulate what data I want to retrieve instead of retrieving everything. Then I invoking by List<SearchResultModel> actual = myPage.GetAllResults(title:true,isPrime:true); in this instance I get a list of SearchResultsModel that each contain only 2 properties - title and isPrime.

In ideal world I should retrieve all the data from the page but it takes lots of time to do so and defeats the whole purpose of automation of being faster then manual testing.

I could use method overload but then I end up with tens or even hundreds methods. In this example I have only 3 property so I will end up having 9 methods, in case of an object with 10 properties, I am afraid to even do a math. I could use varagrs but then building an argument will become a mess. I am not sure how to solve this problem in Java. Please advise

public class SearchResultsModel
{
    //model that represents a single search result item 
    public string Title{get;set;}
    public boolean IsPrime{get;set;}
    public float Price {get;set;]

} 


//method to retrieve all the search results from UI
public List<SearchResultModel> GetAllResults(bool title = false;bool isPrime = false;bool price = false)
{
    List<SearchResultModel> toReturn = new List<SearchResultModel>();
    IList<IWebElement> results =  driver.FindElements(By.css("my locattors"))

    foreach(IWebElement element in results)
    {
        SearchResultModel result = new SearchResultModel();
        result.Title = title? element.FindElement(By.css("some locator")).GetText(): null;
        result.IsPrime = isPrime? element.FindElement(By.css("some locator")).Selected(): false;
        result.Price = price? element.FindElement(By.css("some locator")).GetText(): null;
        toReturn.Add(result);
    }

    return toReturn;
}

//this is how I can invoke objects only with a specific properties

List<SearchResultModel> actual = myPage.GetAllResults(title:true,isPrime:true);

foreach(SearchResultModel model in actual)
{
    Assert.That(model.isPrime == true);
}

1 Answers1

1

I would build a class that represents what options you want to search for. It's basically a parallel to your SearchResultsModel. You pass an instance of that class into the GetAllResults method and then check each property's value to see if it should be pulled or not.

An example of the options class

public class SearchResultsOptions
{
    public boolean Title{get;set;}
    public boolean IsPrime{get;set;}
    public boolean Price {get;set;]
    ...
}

An adapted version of your GetAllResults method

public List<SearchResultModel> GetAllResults(SearchResultsOptions searchResultsOptions)
{
    List<SearchResultModel> toReturn = new List<SearchResultModel>();
    IList<IWebElement> results =  driver.FindElements(By.css("my locattors"))

    foreach(IWebElement element in results)
    {
        SearchResultModel result = new SearchResultModel();
        result.Title = searchResultsOptions.Title? element.FindElement(By.css("some locator")).GetText(): null;
        result.IsPrime = searchResultsOptions.IsPrime? element.FindElement(By.css("some locator")).Selected(): false;
        result.Price = searchResultsOptions.Price? element.FindElement(By.css("some locator")).GetText(): null;
        // add more fields here

        toReturn.Add(result);
    }

    return toReturn;
}

You would have to instantiate the options class and then pass it to your method

SearchResultsOptions searchResultsOptions = new SearchResultsOptions(true, false, true);
List<SearchResultModel> searchResultsModel = GetAllResults(searchResultsOptions);
JeffC
  • 22,180
  • 5
  • 32
  • 55
  • thanks @JeffC, to extend your logic, I can provide booleans in ```public List GetAllResults(boolean title, boolean isPrime, boolean isPrice)``` and then invoke by ```GetAllResults(true, false,true)```. Honestly that is not an ideal method since if a model is pretty large, lets say 15 properties, then I will need to pass 15 booleans as an argument in a proper order, which is pretty easy to mess up. Again, thanks for your answer, I wish there would be a cleaner way(maybe it is language limitation) – Oleksiy Kyrylenko Dec 19 '19 at 15:13
  • Yeah... in C# you can use named parameters which makes everything easier to read so you are less likely to pass a value to the wrong parameter. Java doesn't have that. You could use the Builder Pattern in Java to create your options instance and then pass it to the method. See [this](https://stackoverflow.com/questions/1988016/named-parameter-idiom-in-java/9571371) for a good example. – JeffC Dec 19 '19 at 15:35
  • To your first point... yes you could do it that way but if you package up all the options in a class, it's reusable. I use this method all the time to group say Customer info like first name, last name, address, phone numbers, email, etc. I make one instance and then I can pass the same instance to 5 different methods. A huge advantage and time saver. Creating the instance can be a pain but there's really no way around that. – JeffC Dec 19 '19 at 15:38