2

私はMVCサイトにAreaを持っています。この領域には、通常のコントローラ/モデル/ビューの設定があります。私は、次のコードを持つコントローラとしてエリア内のViewEngineをテストするコントローラをモックする - null参照とRouteData

public class DocumentCreatorController : Controller 
{ 
    // GET: Templates/DocumentCreator 
    public ActionResult OfferTemplate(BaseDocumentViewModel data) 
    { 
     return this.Pdf(nameof(OfferTemplate), data, "File.pdf"); 
    } 
} 

もののカップルを行いますが、興味深いのは、それがダウンViewEngine呼び出しに来ているthis.Pdf方法:

var viewResult = ViewEngines.Engines.FindPartialView(controllerContext, partialViewName); 

ここで私は、 とPartialViewNameとをFindPartialViewと呼んでください。私のPartialViewNameはコントローラアクションOfferTemplatenameof(OfferTemplate)から来ます。私はcontrollercontextが私の挑戦だと思う。

私のチャレンジは

[TestMethod] 
public void OfferTemplate() 
{ 
    var ctr = SetupControllerWithContext(); 

} 

private static DocumentCreatorController SetupControllerWithContext() 
{ 
    var routeData = new RouteData(); 
    routeData.Values.Add("controller", "DocumentCreatorController"); 
    routeData.Values.Add("action", "OfferTemplate"); 


    var request = new Mock<HttpRequestBase>(); 
    request.Expect(r => r.HttpMethod).Returns("GET"); 
    var mockHttpContext = new Mock<HttpContextBase>(); 
    mockHttpContext.Expect(c => c.Request).Returns(request.Object); 
    var controllerContext = new ControllerContext(mockHttpContext.Object 
     , routeData, new Mock<ControllerBase>().Object); 

    DocumentCreatorController ctr = new DocumentCreatorController(); 
    ctr.ControllerContext = controllerContext; 
    return ctr; 
} 

私はユニットテストでこれを設定したい(部品番号を使用して)、私は次のコードなどMocking The RouteData Class in System.Web.Routing for MVC applicationsMocking Asp.net-mvc Controller Contextとしてページに基づいています次のエラーが表示されます。

Eesy.Websites.Api.Tests.Controllers.DocumentCreatorControllerTest.OfferTemplate threw exception: System.NullReferenceException: Object reference not set to an instance of an object.

これはわかりません。

マイフォルダのセットアップ:ControllerContext上

enter image description here

デバッグイメージFindPartialViewを呼び出す上:

enter image description here

誰もがアイデアを持っていますか? RouteDataを間違って設定したためですか?

+1

'routeData.Values.Add(" controller "、" DocumentCreator ");'( "DocumentCreatorController"ではなく) –

+1

フレームワークコードを模擬してテストしようとしています。その機能をコードに抽象化して、必要に応じて単独でテストすることができます。これは[XY問題](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)のようです。あなたが達成しようとしている究極の目標は何ですか? – Nkosi

+0

@Nkosi良い点。私はユニットテストを使用してPDF(HTMLからPDFへ)を自動的に生成しようとしていますので、PDF生成処理の動作を検証できます。コントローラを使用してこれを行うことを望みましたが、明らかに、これを避ける代わりにサービスを作ることが理にかなっています:-) –

答えて

1

フレームワークコードを模擬してテストしようとしています。その機能をコードに抽象化して、必要に応じて単独でテストすることができます。

現在のところ、コントローラは、外部サードパーティの依存関係と緊密に結合されています。コントローラアクションフローを単独でテストすることが目標だった場合は、第三者のPDF生成を抽象化して、簡単にテストできるように嘲笑することをお勧めします。

public interface IDocumentService { 
    ActionResult ToPdf(Controller arg1, string arg2, object arg3, string arg4); 
} 

コントローラは、コンストラクタインジェクションを介してこの抽象化に明示的に依存します。

public class DocumentCreatorController : Controller { 
    private readonly IDocumentService render; 

    DocumentCreatorController(IDocumentService render) { 
     this.render = render; 
    } 

    // GET: Templates/DocumentCreator 
    public ActionResult OfferTemplate(BaseDocumentViewModel data) { 
     return render.ToPdf(this, nameof(OfferTemplate), data, "File.pdf"); 
    } 
} 

だから今、あなたの抽象化をモックのみ必要コントローラのPDF生成プロセスをテストします。

[TestMethod] 
public void OfferTemplate() { 
    //Arrange  
    var serviceMock = new Mock<IDocumentService>(); 
    //...setup mock for use case 

    var controller = new DocumentCreatorController(serviceMock.Object); 
    var data = new BaseDocumentViewModel { 
     //... 
    }; 

    //Act 
    var actual = controller.OfferTemplate(data); 

    //Assert 
    //...assert behavior 
} 

サービスの実際の実装では、実際の機能がカプセル化され、抽象と一緒に依存性注入コンテナに登録されます。

実際の世代をテストするには、別のトピックである統合テストを行う必要があります。

関連する問題