2016-09-20 12 views
-1

私が抱えている問題は、親クラス(BasePage)から継承したクラス(ページ)がたくさんあることです。子クラスを初期化するときはいつでも、WaitForLoadingToStop()というメソッドを実行する必要があります。どのように私はこのメソッドを継承し、それは私の子クラスのコンストラクタへの実装ですか?継承するクラスがそのコンストラクタでメソッドを実装するように強制するにはどうすればいいですか?

これは私が変更が必要なのは、場所のいたるところに複製されているためです。したがって、クラスが作成されたときに自動的に継承され実行されます。

 var assPage = new StudentAssesmentPage(Driver); 
     assPage.WaitForLoadingToStop(); 

これはサンプルの子クラスで、私は以下は、この

public class StudentAssesmentPage : BasePage<StudentAssesmentPageObjectRepository> 
{ 
    public StudentAssesmentPage(IWebDriver driver) : base(driver, new StudentAssesmentPageObjectRepository(driver)) 
    {} 
} 

のように見える10人を持っている私のBasePageクラスクラスはジャスト基本クラスから継承

public abstract class BasePage<TObjectRepository> where TObjectRepository : BasePageObjectRepository 
{ 
    protected WebDriverWait Wait { get; } 
    protected IWebDriver Driver { get; } 
    protected ApplicationUrls ApplicationUrls { get; } 
    public IJavaScriptExecutor JavascriptExecutor { get; } 
    protected Actions UserInteractions { get; private set; } 

    protected By _loadingSpinnerLocator = By.Id("spinner"); 
    private readonly double LOADING_SPINNER_TIMEOUT = 60; 
    private TObjectRepository _objectRepository; 

    public BasePage(IWebDriver driver, TObjectRepository repository) 
    { 
     Driver = driver; 
     _objectRepository = repository; 
     UserInteractions = new Actions(Driver); 
     ApplicationUrls = new ApplicationUrls(); 
     Wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(GetPageTimeout())); 
     JavascriptExecutor = Driver as IJavaScriptExecutor; 
    } 

    internal TObjectRepository ObjectRepository 
    { 
     get { return _objectRepository; } 
    } 

    protected bool WaitForLoadingToStop(int secondsToSleep = 5) 
    { 
     var sleepTime = TimeSpan.FromSeconds(secondsToSleep); 
     Reporter.Debug($"{Helpers.GetCurrentMethodName()}. Going to sleep for:{sleepTime.Seconds}"); 
     Thread.Sleep(sleepTime); 
     Reporter.Debug($"Now, going to wait for loading spinner for:{LOADING_SPINNER_TIMEOUT} seconds."); 
     var basePageWait = new WebDriverWait(Driver, TimeSpan.FromSeconds(LOADING_SPINNER_TIMEOUT)); 
     basePageWait.Message = 
      $"Waited for {LOADING_SPINNER_TIMEOUT}sec for the spinner. However, it took longer than that for the application to load."; 


     return basePageWait.Until(ExpectedConditions.InvisibilityOfElementLocated(By.XPath("//img[@src='/Content/images/spinner.gif']"))); 
    } 
} 
+1

混乱しています... WaitForLoadingToStopは基本クラスの一部ですが、上記のサンプルではインスタンスなしで直接呼び出しています。あなたは 'assPage.WaitForLoadingToStop()...'を意味しましたか? –

+0

おっと、それを指摘してくれてありがとう。 –

+0

あなたの質問は理にかなっていません。 'WaitForLoadingToStop()'は 'protected'ですが、明らかに宣言クラス外のコードから呼び出されていますか?いずれにしても、コンストラクターが時間を浪費するのは悪い考えです。長い初期化を扱う通常の方法は、ファクトリメソッドを書くことです。あなたはそこに待つことができ、さらには全体を非同期にすることもできます。あなたの質問がこれまで述べてきたように、各子クラスのコンストラクタにその呼び出しを入れる以外に、それがどのように動作するかははっきりしません。 –

答えて

-1
public class StudentAssesmentPage : BasePage<StudentAssesmentPageObjectRepository> 
{ 
    public StudentAssesmentPage(IWebDriver driver) : base(driver, new StudentAssesmentPageObjectRepository(driver)) 
    { 
     base.WaitForLoadingToStop(); 
    } 
} 
+0

私は、基本クラスのすべてが手動でメソッドを呼び出さなければならないと考えていたと思います。また、コードのみの回答では、通常、いくつかの説明が役立ちます。 –

+0

私は@AndrewPiliserに同意します。私はすべてのコンストラクタでこのメソッドを呼び出す必要はありません。それは私が修正しようとしているDRY原則に違反しています。 –

1

です実装BasePageThatWaitsForLoadingToStopは、あなたのための仕事をコンストラクタで行います。残っている唯一の定型コードは(この基底クラスに例えばStudentAssesmentPage)特定の実装のコンストラクタの引数を渡している

public class StudentAssesmentPage : BasePageThatWaitsForLoadingToStop 
{ 
    public StudentAssesmentPage(IWebDriver driver) : base(driver, new StudentAssesmentPageObjectRepository(driver)) // this is the only boilerplate code that is left 
    { 

    } 
} 

public class BasePageThatWaitsForLoadingToStop : BasePage<StudentAssesmentPageObjectRepository> 
{ 
    public BasePageThatWaitsForLoadingToStop(IWebDriver driver) : base(driver, new StudentAssesmentPageObjectRepository(driver)) 
    { 
     base.WaitForLoadingToStop(); 
    } 
} 

次のようにあなたは、単にそれを呼び出すことができますし、それが自動的にあなたのための作業を行います。

var assPage = new StudentAssesmentPage(Driver); 

ただし、テストの観点から見ると、コンストラクタで作業するのは理想的ではありません。

+0

この提案をありがとう。質問があります。なぜ新しいクラスではなく、BasePageコンストラクタで同じことをすることができないのですか? –

+0

これも可能です。個人的には、インタフェースを実装する純粋に抽象的な基本クラスの基本実装を持つことで、物事を別々に保つことを好みます(純粋に抽象クラス/メソッドとその基本実装)。この手法を使用すると、たとえば、いくつかのメソッド(デフォルトではオーバーライドできるもの)に対してデフォルトの実装を提供する基本クラスを作成し、他のメソッドでは継承クラスがメソッドを実装できるようにすることができます。 – bergmeister

+0

メインのコメントセクションの他の質問について:私が言ったように、コンストラクタで作業をすると、クラスをテストするのが難しくて高価になります(例:18:00 http://www.youtube.com/watch?v = acjvKJiOvXw)。代わりに依存関係注入(DI)を使用してください。たとえば、DIを使用すると、コンストラクタでその定義プロパティのみを設定し、すべての複雑さを処理するPizzaファクトリに渡されるMargheritaクラスを持つことができます。これにより遅延初期化も可能になります。つまり、多くの注文を取ることができますが、実際に必要な場合にのみ実際に作業を行います。 – bergmeister

関連する問題