2010-05-25 25 views

回答

2

ObjectResult(according to the MSDN docs)是密封類作爲這樣你不能模擬它。懲戒庫,例如起訂量的工作方式是,當你這樣做

Mock<Foo> fooMock = new Mock<Foo>(); 

它生成(使用Reflection.Emit的和其他各種魔術)一類,看起來有點像這樣

public class FooMockingProxy : Foo { 

    public override void This() { 
     // Mocking interceptors to support Verify and Setup 
    } 

    public override string That() { 
     // Mocking interceptors to support Verify and Setup 
    } 

} 

即它需要你想要的類(接口)模擬和子類化(或者在接口的情況下實現它)。這使得它可以放入允許它檢查一個方法是否被調用的儀表,或者返回一個特定的值(這支持各種Setup和Verify方法)。到嘲笑的這種方法的限制是: -

  • 密封類(不能作爲子類)
  • 私有成員(不能從一個子類訪問)
  • 方法或屬性的類是不虛擬的(因此不能被重寫)。

接近密封類時可以採用的一種技術是將它們包裝在某種可摹擬的接口中。或者,您可以嘗試並模擬密封類實現的接口,只有您的代碼消耗。

+0

你可以舉一個例子來說明如何加載這個模擬ObjectResult的值? – KevinDeus 2011-10-05 23:01:14

4

我也有這個問題;我使用數據庫優先設計,EF 4.x DbContext生成器模板來生成我的DbContext。

我修改上下文的生成在以下幾個方面:

  1. 相反DbSet <牛逼>對實體集,我回到IDbSet <牛逼>;這允許我使用InMemoryDbSet <T>進行單元測試(Google用於實現);
  2. 而不是ObjectResult <T>對於存儲過程,我返回IEnumerable <T>。在爲存儲過程創建的虛擬方法中,我將ObjectResult <T>加載到List <T>並返回該值;
  3. 最後,我提取了一個暴露實體集和函數導入的接口。這意味着我可以模擬整個DbContext進行超快速的單元測試。當然,您仍然應該編寫集成測試來測試數據庫的真實功能。
+0

讓你想知道MS何時會意識到這種事情需要通過接口而不是具體的類來暴露。 Grr .... – 2014-08-11 07:57:09

0

ObjectResult通常與Linq一起使用,因此它主要用作IEnumerable。即使對象被封閉,你也可以模擬它並設置IEnumerable行爲。

以下是一些示例代碼,其中TResult是存儲過程結果類型,TDbContext是DbContext,它將返回1個項目。

var valueEnumerator = new TResult[] { new TResult() }.GetEnumerator(); 

var mockStoredProcedure = new Mock<ObjectResult<TResult>(); 
mockStoredProcedure.Setup(x => x.GetEnumerator()).Returns(valueEnumerator); 

var mockEntities = new Mock<TDbContext>(); 
mockEntities.Setup(x => x.[stored procedure method]()).Returns(mockStoredProcedure.Object); 

您可以添加任何值,例如在陣列上方或使用任何其他集合(你只需要枚舉)。

試試這段代碼。它適用於EF 6.1.2和Moq 4.2

+0

GetEnumerator不是虛擬的,因此不可覆蓋。 – niklr 2015-06-03 15:54:56

+0

@niklr GetEnumerator方法是一種可以使用Moq設置的公共方法。你不要用Moq「覆蓋」方法,你嘲笑結果。上面提供的代碼正常工作! – pgk 2015-06-17 19:38:19

+0

這樣做會導致以下異常:'System.NotSupportedException:在非虛擬(VB中可重寫)成員上設置無效:x => x.GetEnumerator()' – 2015-10-05 09:02:27

0

我找不到一種方法來模擬一個密封的類,並且想要測試存儲過程的參數是否與實體模型相匹配。這裏是我的解決方案:

namespace CardiacMonitoringTest 
{ 
    [TestClass] 
    public class CardiacMonitoringDataTest 
    { 
     [TestMethod] 
     public void TestEntityStoredProcedure() 
     { 
      List<string> SPExceptions = new List<string>(); 
      SPExceptions.Add("AfibBurdenByDay"); 
      SPExceptions.Add("GetEventTotalsByCategory"); 

      EntitiesCon db = new EntitiesCon(); 
      foreach (MethodInfo mi in typeof(EntitiesCon).GetMethods()) 
      { 

       string ptype = mi.ReturnType.Name; 
       if (ptype.IndexOf("ObjectResult") > -1) 
       { 
        List<SqlParameter> ExtractedParameters = SPListParm(ConfigurationManager.ConnectionStrings["CardiacMonitoring"].ConnectionString, mi.Name); 
       ExtractedParameters = ExtractedParameters.Where(a => a.ParameterName != "@RETURN_VALUE" && a.ParameterName != "@TABLE_RETURN_VALUE").ToList(); 
       ParameterInfo[] EntityParameters = mi.GetParameters(); 
       if ((from b in SPExceptions where b.ToLower() == mi.Name.ToLower() select b).Count() > 0) 
       { 
        continue; 
       } 
       foreach (ParameterInfo pi in EntityParameters) 
       { 


         try 
         { 
          Assert.IsTrue(
           (from a in ExtractedParameters where pi.Name.ToLower() == a.ParameterName.Replace("@", "").ToLower() select a).Count() == 1); 
         } 
         catch (Exception ex) 
         { 
          Trace.WriteLine("Failed SP:" + mi.Name + " at parameter:" + pi.Name); 
          throw (ex); 
         } 
        try 
        { 
         Assert.IsTrue(EntityParameters.Count() == ExtractedParameters.Count()); 
        } 
        catch (Exception ex) 
        { 
         Trace.WriteLine("Failed SP:" + mi.Name + " on parameter count:" + EntityParameters.Count() + " with detected count as:" + ExtractedParameters.Count()); 
         throw (ex); 
        } 
       } 
      } 
      } 
     } 

     private List<SqlParameter> SPListParm(string ConnectionString, string SPName) 
     { 
      try 
      { 
       SqlConnection conn = new SqlConnection(ConnectionString); 
       SqlCommand cmd = new SqlCommand(SPName, conn); 
       cmd.CommandType = CommandType.StoredProcedure; 
       conn.Open(); 
       SqlCommandBuilder.DeriveParameters(cmd); 
       SqlParameter[] prmDetectParameters = new SqlParameter[cmd.Parameters.Count]; 
       cmd.Parameters.CopyTo(prmDetectParameters, 0); 
       List<SqlParameter> toReturn = new List<SqlParameter>(); 
       toReturn.AddRange(prmDetectParameters); 
       return (toReturn); 
      } 
      catch (Exception ex) 
      { 
       Trace.WriteLine("Failed detecting parameters for SP:" + SPName); 
       throw (ex); 
      } 
     } 
    } 
} 
+2

您是否介意進一步擴展?這看起來像一個代碼轉儲。 – 2016-09-06 13:35:16

+0

這是一個單元測試,通過將ADO.NET連接與反射與實體框架模型進行比較,測試所有存儲過程參數與數據庫中的實際內容是否匹配。它回答我的實體模型是否與數據庫匹配。 – 2018-01-11 14:33:39