Fake Assembly 無法自動產生 *.Fakes dll 及出現 build fail

如何 Mock System.Web.Hosting.HostingEnvironment.MapPath 虛擬路徑 提到同事想要 mock System.Web.Hosting.HostingEnvironment.MapPath 的值,試了半天決定用 fake dll 的方法來直接解決,但過程不太順利,所以留下紀錄

重現問題:無法出現 System.Web.Fakes/System.Web.Http.Fakes dll

  1. 加入 Fakes assembly

    • 開啟測試專案的 References 資料夾
    • System.Web.Http 上按右鍵 –> Add Fakes Assembly

      1addfake

  2. 未出現 System.Web.Http.Fakes/System.Web.Fakes dll

    • Fakes 資料夾已產生 System.Web.Http.fakes/System.Web.fakes 的設定檔
    • References 資料夾則沒有出現對應版本的 System.Web.Http.{版本}.Fakes/System.Web.{版本}.Fakes dll

      2without

錯誤訊息 1:CS0430

  1. 訊息內容

    Error    CS0430    The extern alias 'swhod' was not specified in a /reference option [C:\Users\yowko.tsai\documents\visual studio 2015\Projects\DemoUnitTesting\DemoWebApiTesting.Tests\obj\Debug\Fakes\swh\f.csproj]    DemoWebApiTesting.Tests    C:\Users\yowko.tsai\documents\visual studio 2015\Projects\DemoUnitTesting\DemoWebApiTesting.Tests\f.cs    19    Active
       
    Error        project compilation failed with exit code 1    DemoWebApiTesting.Tests    C:\Users\yowko.tsai\documents\visual studio 2015\Projects\DemoUnitTesting\DemoWebApiTesting.Tests\GENERATEFAKES        
       
    Error        project compilation failed with exit code 1    DemoWebApiTesting.Tests    C:\Users\yowko.tsai\documents\visual studio 2015\Projects\DemoUnitTesting\DemoWebApiTesting.Tests\GENERATEFAKES        
    
  2. 錯誤截圖

6buildfail

  1. 解決方式

    • System.Web.Http

      1. 開啟 Fakes 資料夾中的 System.Web.Http.fakes 設定檔

        3fakesconfig

        4fakesconfigcontent

      2. 加入下列設定

        <StubGeneration>
            <Clear />
            <Add Interfaces="true"/>
        </StubGeneration>
        <ShimGeneration>
            <Clear />
            <Add Namespace="System.Web.Http.ExceptionHandling"/>
        </ShimGeneration>
        
      3. 設定前後比較

        • 修改前

          <Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
            <Assembly Name="System.Web.Http" Version="5.2.3.0"/>
          </Fakes>
          
        • 修改後

          <Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
            <Assembly Name="System.Web.Http" Version="5.2.3.0"/>
            <StubGeneration>
              <Clear />
              <Add Interfaces="true"/>
            </StubGeneration>
            <ShimGeneration>
              <Clear />
              <Add Namespace="System.Web.Http.ExceptionHandling"/>
            </ShimGeneration>
          </Fakes>
          
    • System.Web

      1. 開啟 Fakes 資料夾中的 System.Web.fakes 設定檔
      2. 加入下列設定

        <StubGeneration>
            <Clear />
            <Add Interfaces="true"/>
        </StubGeneration>
        <ShimGeneration>
            <Clear />
            <Add Namespace="System.Web"/>
        </ShimGeneration>
        
      3. 設定前後比較

        • 修改前

          <Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
            <Assembly Name="System.Web" Version="4.0.0.0"/>
          </Fakes>
          
        • 修改後

          <Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
            <Assembly Name="System.Web" Version="4.0.0.0"/>
            <StubGeneration>
              <Clear />
              <Add Interfaces="true"/>
            </StubGeneration>
            <ShimGeneration>
              <Clear />
              <Add Namespace="System.Web"/>
            </ShimGeneration>
          </Fakes>
          
    • 重新執行產生 fake dll

      1. 找個任意其他的 dll 再執行 Add Fakes Assembly一次
      2. 可以使用測試目標的 dll or anyone else 執行後就會出現

        5anotherfake

      3. 刪除不需要的 fake dll 跟 設定檔

        7success

錯誤訊息:CS0234

  1. 訊息內容

    Error    CS0234    The type or namespace name 'EventSourceCreatedEventArgs' does not exist in the namespace 'System.Diagnostics.Tracing' (are you missing an assembly reference?) [C:\Users\yowko.tsai\documents\visual studio 2015\Projects\TestFakeError\TestFakeError.Tests\obj\Debug\Fakes\m\f.csproj]    TestFakeError.Tests    C:\Users\yowko.tsai\documents\visual studio 2015\Projects\TestFakeError\TestFakeError.Tests\f.cs    17698    Active
    
    Error        project compilation failed with exit code 1    TestFakeError.Tests    C:\Users\yowko.tsai\documents\visual studio 2015\Projects\TestFakeError\TestFakeError.Tests\GENERATEFAKES        
    Error        project compilation failed with exit code 1    TestFakeError.Tests    C:\Users\yowko.tsai\documents\visual studio 2015\Projects\TestFakeError\TestFakeError.Tests\GENERATEFAKES        
    
  2. 錯誤畫面

    8mscorliberror

  3. 解決方式

    • 開啟 Fakes 資料夾中的 mscorlib.fakes 設定檔
    • 加入下列設定

      <StubGeneration>
          <Remove FullName="System.Diagnostics.Tracing"/>
          <Remove FullName="System.Text.Encoding"/>
          <Remove FullName="System.Security.Cryptography" />
      </StubGeneration>
      
    • 設定前後比較

      • 修改前

        <Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
          <Assembly Name="mscorlib" Version="4.0.0.0"/>
        </Fakes>
        
      • 修改後

        <Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
          <Assembly Name="mscorlib" Version="4.0.0.0"/>
          <StubGeneration>
            <Remove FullName="System.Diagnostics.Tracing"/>
            <Remove FullName="System.Text.Encoding"/>
            <Remove FullName="System.Security.Cryptography" />
          </StubGeneration>
        </Fakes>
        

錯誤訊息:Unexpected error returned by SetDetourProvider

  1. 訊息內容

    Microsoft.QualityTools.Testing.Fakes.UnitTestIsolation.UnitTestIsolationException
    "Unexpected error returned by SetDetourProvider in profiler library 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\IntelliTrace\14.0.0\Microsoft.IntelliTrace.Profiler.14.0.0.dll'."
    
  2. 錯誤畫面

    9intellitrace

  3. 解決方式

    • 關閉 IntelliTrace 的 call information

      1. Visual Studio 主選單 Tools tab –> Options…

        10vstools

      2. IntelliTrace –> General (下列兩個方式擇一即可)

        11disablecallinfo

        • uncheck Enable IntelliTrace
        • IntelliTrace events only

參考資料

  1. Fakes issue with System.Web.Http
  2. Fakes Issue with System.Web