Resolved How to create abstraction of a file which has too many methods

Palak Shah

Well-known member
Joined
Apr 29, 2020
Messages
97
Programming Experience
1-3
Hello Everyone,

I have one file which is of common method and has too many methods inside a single class file, now I want to create hierarchy so it can be divided further with the help of abstraction, I tried few things but then I got confused on how to access different methods?

Main Common Methods file which has lot of methods:
using Base;
using Constants;
using Entities;
using Extensions;
using SeleniumExtensions;
using Helpers;
using Model;
using AtlasNav;
using Model.PaymentOptions;
using Pages.DesignPages.DesignViews;
using Pages.UserAccount_Pages;
using Repositories;
using Pages;
using Pages.CheckoutPages;
using Pages.CMSPages;
using Pages.KlarnaCheckoutPages;
using Pages.SellerStorePages;
using Framework.DataAccessLayer.EntitiyFramework.Repositories;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using TestConfigurationCDO = Config.TestConfigurationCDO;

namespace ManualRegressionSuite.CommonMethods
{   public class CommonMethods : Base
    {
        public TestConfigurationCDO _testConfiguration;
        WebDriverWait wait;
        public IList<Site> _sites;
        public string _bolUkSiteUrl;
        public string _cmsSiteUrl;
        public Site _site;

        public CommonMethods(SharedParameters test_properties)
        {
            this.shared_parameters = test_properties;
            this.Driver = test_properties.Driver;
            this._testConfiguration = test_properties.testConfiguration;
            this._sites = test_properties.sites;
            this._bolUkSiteUrl = test_properties.SiteBag.domain_url;
            this._cmsSiteUrl = test_properties.SiteBag.cms_url;
            this._site = test_properties.site;
        }
        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_SellerLogIn()
        {
            var site = shared_parameters.site.GetName();

            var homePage = GetInstance<HomePage>();
            homePage.To_SignInPage(site);

            var signInPage = GetInstance<SignInPage>();
            signInPage.To_SellerLandingPage();
        }
        /// <summary>
        /// Below method will navigate to Product Page through Atlas Navigation
        /// </summary>
        /// <param name="productId"></param>
        public void CommonMetho_GoToProductPage(int productId)
        {
            var homePage = GetInstance<HomePage>();
            homePage.To_ProductPage(productId);
        }
        /// <summary>
        /// Below method will:
        ///
        /// </summary>
        /// <param name="param"></param>
        public void CommonMethod_DesignProduct(WorkflowParameters param)
        {
            var generalProductPage = GetInstance<MasterProductPage>();
            generalProductPage.To_DesignPage();

            var designPage = GetInstance<DesignPage, DesignPageArgs>(new DesignPageArgs());
            designPage.basketToolbarView.UpdateProductQuantity(param.quantity.ToString());
            
            designPage.Design(param.designMethod);
        }
        /// <summary>
        /// Below method will Add product to Basket
        /// </summary>
        public void CommonMethod_AddToBasket()
        {
            var designPage = GetInstance<DesignPage, DesignPageArgs>(new DesignPageArgs());
            designPage.AddToCart();
        }
        /// <summary>
        /// Below method will review the basket item:
        /// </summary>
        /// <param name="productId"></param>
        public void CommonMethod_BasketReview(int productId)
        {
            var basketPage = GetInstance<BasketPage, BasketPageArgs>(new BasketPageArgs());

            var check = basketPage.BasketPriceView.CheckBasketPrice();
            Assert.IsTrue(check);

            var isPresent = basketPage.BasketItemsView.Validate_ItemIsInBasket(productId);
            Assert.IsTrue(isPresent);

            Assert.IsTrue(!ImageHelpers.IsEmpty(basketPage.BasketItemsView.GetItemImage(productId)));
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public string CommonMethod_PurchaseItem(WorkflowParameters param)
        {
            var basketPage = GetInstance<BasketPage, BasketPageArgs>(new BasketPageArgs());

            basketPage.To_CheckoutPage(param.paymentOptions.portal);

            var checkoutPage = GetInstance<CheckoutPage>();
            checkoutPage.To_OrderSummaryPage(param.paymentOptions);
            
            var orderConfirmPage = GetInstance<OrderConfirmPage>();
            var _order = orderConfirmPage.To_Self_CheckOrderDatabase();

            return _order.OrderId.ToString(); ;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="OrderId"></param>
        public void CommonMethod_CMSVerification(string OrderId)
        {
            var cmsLoginPage = GetInstance<CMSLoginPage>();
            cmsLoginPage.To_CMSLandingPage();

            var cmsLandingPage = GetInstance<CMSLandingPage>();
            cmsLandingPage.To_OrderPage_OrderCheck(OrderId);

            var cmsOrderPage = GetInstance<CMSOrderPage>();
            cmsOrderPage.orderDetailsView.To_Self_CheckPrices(shared_parameters.price);
            
            var check = cmsOrderPage.orderDetailsView.IsOrderAuthorised(OrderId.ToInt());
            Assert.IsTrue(check);
        }
        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_CMSDespatchNoteVerification()
        {
            var cmsOrderPage = GetInstance<CMSOrderPage>();
            cmsOrderPage.ChangeStatus_ByDropDown(OrderStatus.Dispatched);

            cmsOrderPage.deliveryDetailsView.Check_DespatchNote();
        }
        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_CreateStore()
        {
            var sellerLandingPage = GetInstance<SellerLandingPage>();
            sellerLandingPage.To_SellerMyStoresPage();

            var sellerMyStoresPage = GetInstance<SellerMyStoresPage>();
            var uniqueName = sellerMyStoresPage.To_Self_CreateStore();
        }
        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_NavigateToMyProductsPage()
        {

        }
        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_CreateProduct()
        {

        }
        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_AddProductToStore()
        {

        }
    }
    public class WorkflowParameters
    {
        public int productId = default(int);
        public int orderId = default(int);
        public DesignMethod designMethod = default(DesignMethod);
        public bool signedIn = default(bool);
        public bool increaseBasketQty = default(bool);
        public bool signedInCMS = default(bool);
        public bool editable = default(bool);
        public Site _site = default(Site);
        public PaymentOptions paymentOptions = default(PaymentOptions);
        public bool checkOrderAuthorise = default(bool);
        public int quantity = default(int);
    }
}


Now I want to create hierarchy such that main file common method will have on definitions of method and 2 separate class files will be there one for CMS Common Methods and one for WebSite Common methods


CMSCommonMethod File:
using Base;
using Constants;
using Extensions;
using Pages.CMSPages;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ManualRegressionSuite.CommonMethods
{
    public class CMSCommonMethods : Base
    {
        /// <summary>
        ///
        /// </summary>
        /// <param name="OrderId"></param>
        public void CommonMethod_CMSVerification(string OrderId)
        {
            var cmsLoginPage = GetInstance<CMSLoginPage>();
            cmsLoginPage.To_CMSLandingPage();

            var cmsLandingPage = GetInstance<CMSLandingPage>();
            cmsLandingPage.To_OrderPage_OrderCheck(OrderId);

            var cmsOrderPage = GetInstance<CMSOrderPage>();
            cmsOrderPage.orderDetailsView.To_Self_CheckPrices(shared_parameters.price);

            var check = cmsOrderPage.orderDetailsView.IsOrderAuthorised(OrderId.ToInt());
            Assert.IsTrue(check);
        }
        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_CMSDespatchNoteVerification()
        {
            var cmsOrderPage = GetInstance<CMSOrderPage>();
            cmsOrderPage.ChangeStatus_ByDropDown(OrderStatus.Dispatched);

            cmsOrderPage.deliveryDetailsView.Check_DespatchNote();
        }
    }
}

WebSiteCommonMethod:
using Base;
using Entities;
using Helpers;
using Pages;
using Pages.CheckoutPages;
using Pages.SellerStorePages;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ManualRegressionSuite.CommonMethods
{
    public class WebSiteCommonMethods:Base
    {
        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_SellerLogIn()
        {
            var site = shared_parameters.site.GetName();

            var homePage = GetInstance<HomePage>();
            homePage.To_SignInPage(site);

            var signInPage = GetInstance<SignInPage>();
            signInPage.To_SellerLandingPage();
        }
        /// <summary>
        /// Below method will navigate to Product Page through Atlas Navigation
        /// </summary>
        /// <param name="productId"></param>
        public void CommonMetho_GoToProductPage(int productId)
        {
            var homePage = GetInstance<HomePage>();
            homePage.To_ProductPage(productId);
        }
        /// <summary>
        /// Below method will:
        ///
        /// </summary>
        /// <param name="param"></param>
        public void CommonMethod_DesignProduct(WorkflowParameters param)
        {
            var generalProductPage = GetInstance<MasterProductPage>();
            generalProductPage.To_DesignPage();

            var designPage = GetInstance<DesignPage, DesignPageArgs>(new DesignPageArgs());
            designPage.basketToolbarView.UpdateProductQuantity(param.quantity.ToString());

            designPage.Design(param.designMethod);
        }
        /// <summary>
        /// Below method will Add product to Basket
        /// </summary>
        public void CommonMethod_AddToBasket()
        {
            var designPage = GetInstance<DesignPage, DesignPageArgs>(new DesignPageArgs());
            designPage.AddToCart();
        }
        /// <summary>
        /// Below method will review the basket item:
        /// </summary>
        /// <param name="productId"></param>
        public void CommonMethod_BasketReview(int productId)
        {
            var basketPage = GetInstance<BasketPage, BasketPageArgs>(new BasketPageArgs());

            var check = basketPage.BasketPriceView.CheckBasketPrice();
            Assert.IsTrue(check);

            var isPresent = basketPage.BasketItemsView.Validate_ItemIsInBasket(productId);
            Assert.IsTrue(isPresent);

            Assert.IsTrue(!ImageHelpers.IsEmpty(basketPage.BasketItemsView.GetItemImage(productId)));
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public string CommonMethod_PurchaseItem(WorkflowParameters param)
        {
            var basketPage = GetInstance<BasketPage, BasketPageArgs>(new BasketPageArgs());

            basketPage.To_CheckoutPage(param.paymentOptions.portal);

            var checkoutPage = GetInstance<CheckoutPage>();
            checkoutPage.To_OrderSummaryPage(param.paymentOptions);

            var orderConfirmPage = GetInstance<OrderConfirmPage>();
            var _order = orderConfirmPage.To_Self_CheckOrderDatabase();

            return _order.OrderId.ToString(); ;
        }

        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_CreateStore()
        {
            var sellerLandingPage = GetInstance<SellerLandingPage>();
            sellerLandingPage.To_SellerMyStoresPage();

            var sellerMyStoresPage = GetInstance<SellerMyStoresPage>();
            var uniqueName = sellerMyStoresPage.To_Self_CreateStore();
        }
        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_NavigateToMyProductsPage()
        {
  
        }
        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_CreateProduct()
        {

        }
        /// <summary>
        ///
        /// </summary>
        public void CommonMethod_AddProductToStore()
        {

        }
    }
}

I am not sure for such thing what could be the proper architecture so that if in future we want to scale, it won't have any issue
 
Are you sure a hierarchy is even needed or appropriate? Looking at your code chunks #2 and #3, I'm not seeing anything that jumps out as something shared between the two of them and therefore a good candidate for the beginnings of an interface definition or abstract methods to be implemented by your child classes.

Anway, back in the bad old days when people didn't really understand object oriented programming, inheritance was thought of primarily as a code sharing and data sharing mechanism to minimize the amount of duplicate code. That is you would have something like this:
C#:
class Base
{
    // public methods common to Foo and Bar
    // protected methods that would be used by both Foo and Bar
}

class Foo : Base
{
    // public methods specific to Foo (and may call protected methods on Base)
}

class Bar : Base
{
    // public methods specific to Bar (and may call protected methods on Base)
}
People learned that this would lead to fragile hierarchies (specially in C++ where if you touched a lower level class you had to recompile the world even if you didn't touch any function signatures) and is one of the main complaints people have object oriented programming.

People started learning that inheritance should be used primarily for L in SOLID -- Liskov's substitution principle, and only for code sharing if the stars align. That changes the above to something like:
C#:
abstract class Base
{
    // public abstract methods common Foo and Bar must expose
    // public methods common to Foo and Bar and needs no specialization
    // protected methods that would be used by both Foo and Bar
}

class Foo : Base
{
    // implementation of abstract methods that Foo and Bar must expose with specializaton for Foo
    // public methods specific to Foo (and may call protected methods on Base)
}

class Bar : Base
{
    // implementation of abstract methods that Foo and Bar must expose with specializaton for Bar
    // public methods specific to Bar (and may call protected methods on Base)
}

What Liskov's substitution principle emphasises is the interface that you use to talk to an object. If you use Autofac or some other IoC system, interfaces are what you talk to primarily, and the class implementing them then becomes incidental, so you end up with:
C#:
interface IFooBar
{
    // methods common to Foo and Bar
}

interface IFoo : IFooBar
{
    // methods specific to Foo
}

interface IBar : IFooBar
{
    // methods specific to Bar
}

class Foo : IFoo
{
    // implement IFooBar
    // implement IFoo
}

class Bar : IBar
{
    // implement IFooBar
    // implement IBar
}

Yikes, but now we have duplicate the code between Foo and Bar. And so that will lead to either:
C#:
static class FooBarHelpers
{
    // common method implementation between Foo and Bar 
}

class Foo : IFoo
{
    // implement IFooBar by call FooBarHelpers
    // implement IFoo
}

class Bar : IBar
{
    // implement IFooBar by call FooBarHelpers
    // implement IFoo
}

or like previously with the abstract base class but adding in interfaces:

C#:
abstract class Base : IFooBar
{
    // public abstract methods common Foo and Bar must expose
    // public methods common to Foo and Bar and needs no specialization
    // protected methods that would be used by both Foo and Bar
}

class Foo : Base, IFoo
{
    // implementation of abstract methods that Foo and Bar must expose with specializaton for Foo
    // public methods specific to Foo (and may call protected methods on Base)
}

class Bar : Base, IBar
{
    // implementation of abstract methods that Foo and Bar must expose with specializaton for Bar
    // public methods specific to Bar (and may call protected methods on Base)
}

(There is also the alternative of using default interface methods, but IMHO that should really be used for when you have already released your interface to the big wide world. While you are still working in privately in house, get the interface right and don't use this as a crutch.)

As a quick aside, get rid of the smurf naming convention. You already have the class named CommonMethods. There is no need to name each method in the class CommonMethod_foo.
 
Partial classes is not a design pattern. It just lets you organize things into multiple files instead of one giant file, or let you have some handwritten code combined with some generated code.
 
Now that I am not running a 100.7 degree fever, I can think a little clearer now: another approach is to use the Command design pattern. Instead of getting the related methods together in a class, you would have one Execute() method per class. Each class represents an operation. All the related operations that share common code can derive from a common base class.
 
@Sheepings turned me on to this great web site that has great illustrations and explanations about Design Patterns that is much more accessible than the old GoF book, and a few other sites I've found in the past.


In the text there the emphasis is on using the Command pattern to isolate and encapsulate the operation that needs to be performed. It's a behavioral pattern, but it looks like you are looking more for structural pattern to keep your code more organized.
 
Thank you @Skydiver for your help, One doubt is it good to use partial class design pattern than abstaction?
That's a great question, but it really comes down to what type of application it is that you happen to be running, and for me, ultimately what you are trying to achieve normally dictates the development pattern for me. It's also a discussion which could go on for hours, as there is os much context which could be added to this topic subject. A great place to start understanding the different patterns is to read the above link shared by Skydiver. If I recall that was the link I gave him when he was designing his Blake Encryption project? Some day I'm going to replicate all of the information on that site, and put it on my own website so it never gets lost!
 
From what I can glean from the OP, he is not trying write an application, but rather trying to figure out how to organize his unit tests.
 
Rather than me commonly making mistakes as of recent, I was actually meaningfully making a point. In any respect, the same advice stands. If OP is into learning patterns, then I would suggest no other link than the one given. :)
 
@Sheepings turned me on to this great web site that has great illustrations and explanations about Design Patterns that is much more accessible than the old GoF book, and a few other sites I've found in the past.


In the text there the emphasis is on using the Command pattern to isolate and encapsulate the operation that needs to be performed. It's a behavioral pattern, but it looks like you are looking more for structural pattern to keep your code more organized.
Oh my god!!! it is amazing website!!!!!
 
@Sheepings turned me on to this great web site that has great illustrations and explanations about Design Patterns that is much more accessible than the old GoF book, and a few other sites I've found in the past.


In the text there the emphasis is on using the Command pattern to isolate and encapsulate the operation that needs to be performed. It's a behavioral pattern, but it looks like you are looking more for structural pattern to keep your code more organized.
Yes, and I'm confuse in how to organize the above mentioned class
 
@Skydiver , @Sheepings - I've gone through many patterns but though partial class is not a pattern and at present if I have to organise it the class can I use it? - Though in partial class also I'm not much aware regarding proper implementation - Would really love to hear your thoughts on this
 
@Skydiver , @Sheepings - Your reference website link really helps in understanding concepts clearly thank you so much...:) would love to connect with you guys on any social media platform or through your websites..please do share it :)
 
I'm glad you like the site. As I said it's my virtual good twin @Sheepings who turned me on to it. (I was trying to describe the composite pattern to him and my plan to use it in a behavioral way to get some parallel processing done, rather than a structural way that the pattern is normally used, and he linked me to the site.)

I only have Twitter. I would close by FB account by I grudgingly keep it open for my parents.

And yes splitting code into multiple files is such an old practice across many languages that I don't think there maybe a name for it. In C#, it just happens to make use of partial classes because it doesn't have the equivalent of C/C++ #include.
 
Back
Top Bottom