2017-02-09 11 views
1

静的メソッドで作成されたオブジェクトをモックにすることはできません。 は、ここに私のMOQとコードであるMoq静的クラスのオブジェクト

コード:

public interface IConfigHelper 
{ 
    string GetConfiguration(string sectionName, string elementName); 
} 

public class ConfigHelper : IConfigHelper 
{ 
    public ConfigHelper() { } 

    public virtual string GetConfiguration(string sectionName, string elementName) 
    { 
     string retValue = String.Empty; 
     //Does things to get configuration and return a value  
     return retValue; 
    } 
} 

public class myRealClass 
{ 
    public myRealClass(){} 
    public string myworkingMethod() 
    { 
     var retValue = String.Empty; 
     retValue = utilSvc.GetConfigurationValue(); 
     return retValue; 
    } 
} 

public static class utilSvc 
{ 
    public static string GetConfigurationValue() 
    { 
     ConfigHelper configUtil = new ConfigHelper(); //NOT BEING MOCKED 
     return configUtil.GetConfiguration("sectionName/sectionElement", "ClinicalSystem"); 
    } 
} 

[TestFixture(TestName = "Tests")] 
public class Tests 
{ 
    private Mock<IConfigHelper> configHelperMOCK; 
    [SetUp] 
    public void Setup() 
    { 
     configHelperMOCK = new Mock<IConfigHelper>(); 
    } 

    [Test] 
    public void serviceIsBPManagementForValidSource() 
    { 
     //Arrange 
     string sectionName = "sectionName/sectionElement"; 
     string clinicalElementName = "ClinicalSystem"; 
     string clinicalElementValue = "Zedmed"; 
     configHelperMOCK.Setup(s => s.GetConfiguration(sectionName, clinicalElementName)).Returns(clinicalElementValue); 

     //act 
     // the call to myRealClass 

     //assert 
     // test assertions 
    } 
} 
部品番号

を使用してテストを

私が午前問題は、この行を次のとおりです。

ConfigHelper configUtil = new ConfigHelper(); //NOT BEING MOCKED 

Iオブジェクトをモックするためにmoqを取得することはできません。 私は、コードが設定ファイルを読み込まないようにします。私はこのインスタンスをmoqから外したいですConfigHelper

答えて

0

静的クラスをモックすることはできません。むしろをmyRealClassに注入するように提案したいと思います。これは依存関係を切り離してDIを使用する通常の方法です。

public class myRealClass 
{ 
    private IConfigHelper _configHelper; 

    public myRealClass(IConfigHelper configHelper) 
    { 
    _configHelper = configHelper; 
    } 

    public string myworkingMethod() 
    { 
    var retValue = String.Empty; 
    retValue = _configHelper.GetConfigurationValue(); 
    return retValue; 
    } 
} 
+0

に、私は静的クラスをモックしようとしているわけではない、それをリダイレクトすることができます!私は静的メソッド内で作成されたクラスを模擬しようとしています。このメソッドは、NinjectのBind <>()。WithConstructorArgumentで使用されるメソッドであるため静的です。静的でなければなりません。 – GregJF

+0

オブジェクトを挿入する必要があります。また、並列性を持たずにテストを実行していることを確認してください。多くのテストランナーがテストを並行して実行します。静的クラスを使用する場合は安全ではありません。 –

+0

また、クラスが静的であるという点では、代わりにシングルトンにすることができます。したがって、静的な単一インスタンスをプログラムで使用できるようにしながら、テスト用のインスタンスをインスタンス化できます。 –

0

コードを静的クラスに結合しないでください。ほとんどの場合、コードの保守やテストが難しくなります。

Explicit Dependencies Principle

メソッドとクラスは任意の協調は、彼らが正常に機能するために必要な オブジェクト(通常は メソッドのパラメータまたはコンストラクタのパラメータによって)明示的に要求すべきである従ってください。

記事を読んでください。それは短く、非常に有益です。

静的クラスを保持したい場合は、静的クラスを抽象化の後ろにラップします。

public interface IUtilSvc { 
    string GetConfigurationValue(); 
} 

public class utilSvcWrapper : IUtilSvc { 
    public string GetConfigurationValue() { 
     return utilSvc.GetConfigurationValue(); //Calling static service 
    } 
} 

それとも別のオプションは、依存クラスにIUtilScvを注入依存クラス

public class utilSvc : IUtilScv { 
    private readonly IConfigHelper configUtil; 

    public utilSvc(IConfigHelper configHelper) { 
     configUtil = configHelper; 
    } 

    public string GetConfigurationValue() { 
     return configUtil.GetConfiguration("sectionName/sectionElement", "ClinicalSystem"); 
    } 
} 

に注入することができるならば、それはもはや静的クラスに依存しないようにutlSvcは静的である必要はないことです。その場合

public class myRealClass { 
    private readonly IUtilScv utilSvc; 

    //Explicit dependency inject via constructor 
    public myRealClass(IUtilScv utilSvc) { 
     this.utilSvc = utilSvc; 
    } 

    public string myworkingMethod() { 
     var retValue = utilSvc.GetConfiguration(); 
     return retValue; 
    } 
} 

、それはまた、抽象化されているようにテストするときにあなたもIConfigHelperを必要としません。そして、テストに必要な依存関係だけを模擬する必要があります。

[TestFixture(TestName = "Tests")] 
public class Tests { 
    private Mock<IUtilScv> utilScvMOCK; 

    [SetUp] 
    public void Setup() { 
     utilScvMOCK = new Mock<IUtilScv>(); 
    } 

    [Test] 
    public void serviceIsBPManagementForValidSource() { 
     //Arrange 
     var expectedClinicalElementValue = "Zedmed"; 
     utilScvMOCK 
      .Setup(s => s.GetConfiguration()) 
      .Returns(expectedClinicalElementValue) 
      .Verifiable();    

     var sut = new myRealClass(utilScvMOCK.Object); 

     //Act 
     var actualClinicalElementValue = sut.myworkingMethod(); 

     //Assert 
     configHelperMOCK.Verify(); 
     Assert.AreEqual(expectedClinicalElementValue, actualClinicalElementValue); 
    } 
} 
+0

私は、明示的従属性原則を理解し、それに従い、使用します。 ConfigHelperはmyRealClassの依存関係ではありません。これはutilSvcに依存します。 utilSvcのメソッドは、NinjectのBind <>()によって使用されるメソッドであるため静的です。WithConstructorArgumentは静的でなければなりません – GregJF

+0

@GregJFあなたのコメントに基づいて@GregJFのチェックを更新しますか? – Nkosi

+0

静的なクラス/メソッドをラップできません。 NinjectのBind <>()。WithConstructorArgumentによって呼び出される必要があります。それには静的メソッドが必要です。その静的メソッドから私はConfigHelperを作成して設定を読み込みます。私はConfigHelperを模擬したい – GregJF

1

あなたは静的なクラス/メソッドをラップすることはできませんが、

public static class UtilSvc 
{ 
    static UtilSvc() 
    { 
     CreatorFunc =() => new ConfigHelper(); 
    } 

    public static Func<IConfigHelper> CreatorFunc { get; set; } 

    public static string GetConfigurationValue() 
    { 
     var configUtil = CreatorFunc(); 
     return configUtil.GetConfiguration("sectionName/sectionElement", 
              "ClinicalSystem"); 
    } 
} 

し、テスト

//... 
private Mock<IConfigHelper> configHelperMOCK; 

[SetUp] 
public void Setup() 
{ 
    configHelperMOCK = new Mock<IConfigHelper>(); 
    UtilService.CreatorFunc =() => configHelperMOCK.Object; 
} 
//... 
+0

私はオブジェクトに悪いです。更新されます。しかし、インタフェースのコメントについてはあまり確かではありません。 UtilSvc.GetConfigurationValue()が呼び出されると、これはnew-edインスタンスではなくmockインスタンスを返します。私は何が欠けていますか? – AlanT

+0

ありがとうございます。 IDE以外の電話機でこれを行う際の問題は? – AlanT

+0

うん、それはFunc でなければならない。かわった。 – AlanT

関連する問題