2017-01-18 8 views
0

Also versuche ich einen einfachen Tablecontroller Unit Test für mein Backend zu schreiben ??TableControllers Komponententest

Ich habe es nicht geschafft, alles, was ich erreicht habe, ist Schreiben von Unit-Tests für ApiControllers, aber gibt es eine Möglichkeit, einen Unit-Test für TableControllers zu schreiben?

Was ich möchte, ist, dies zu tun:

public class AuctionController : TableController<Auction> 
{ 
    protected override void Initialize(HttpControllerContext controllerContext) 
    { 
     base.Initialize(controllerContext); 
     MobileServiceContext context = new MobileServiceContext(); 
     DomainManager = new EntityDomainManager<Auction>(context, Request); 
    } 

    // GET tables/Auction 
    public IQueryable<Auction> GetAllAuction() 
    { 
     return Query(); 
    } 

    // GET tables/Auction/48D68C86-6EA6-4C25-AA33-223FC9A27959 
    public SingleResult<Auction> GetAuction(string id) 
    { 
     return Lookup(id); 
    } 

    // PATCH tables/Auction/48D68C86-6EA6-4C25-AA33-223FC9A27959 
    public Task<Auction> PatchAuction(string id, Delta<Auction> patch) 
    { 
     return UpdateAsync(id, patch); 
    } 

    // POST tables/Auction 
    public async Task<IHttpActionResult> PostAuction(Auction item) 
    { 
     Auction current = await InsertAsync(item); 
     return CreatedAtRoute("Tables", new { id = current.Id }, current); 
    } 

    // DELETE tables/Auction/48D68C86-6EA6-4C25-AA33-223FC9A27959 
    public Task DeleteAuction(string id) 
    { 
     return DeleteAsync(id); 
    } 
} 

und ich wünsche einen Test-Controller wie diese zu machen:

[TestClass] 
public class AuctionControllerTests 
{ 
    private readonly AuctionController _controller; 

    public AuctionControllerTests() 
    { 
     _controller = new AuctionController(); 
    } 

    [TestMethod] 
    public void Fetch_all_existing_items() 
    { 
     Assert.Equal(2, _controller.GetAllTodoItems().ToList().Count); 
    } 
} 

wie kann ich möglicherweise in der Lage sein, dies zu erhalten, Arbeit??? Bitte ich würde Ihre Hilfe sehr schätzen.

Antwort

1

so Danke für die spöttische Lösung, es funktionierte, aber ich schrieb eine generische bessere Lösung ohne spöttische Framework, ich anwenden werde später Rahmen verspotten, gerade jetzt ich mit Fake haftet und Echt dbs für die Integration n Tests.

aber zuerst Ich schrieb einen Generic TableController, um mehrere EntityData und DbContext für diejenigen anzuwenden, die mehr als einen Kontext hatten, auch konnten Sie einen FakeContext dank der Abstraktion von Schnittstellen anwenden, aber ich habe nicht auf dieses Beispiel angewendet.

Erste Dies ist meine Base:

//This is an abstract class so we can apply inheritance to scalfolded tablecontrollers<T>. 
public abstract class BaseController<TModel, TDbContext> : TableController<TModel> where TModel : class, ITableData 
                         where TDbContext:DbContext, new() 
{ 
    protected override void Initialize(HttpControllerContext controllerContext) 
    { 
     base.Initialize(controllerContext); 
     var context = new TDbContext(); 
     SetDomainManager(new EntityDomainManager<TModel>(context, Request)); 
    } 

    public void SetDomainManager(EntityDomainManager<TModel> domainManager) 
    { 
     DomainManager = domainManager; 
    } 
} 

dies ist mein scalfolded Controller mit meiner Base angewandt !!!

public class AuctionController : BaseController<Auction, MobileServiceContext>  
{   
    public IQueryable<Auction> GetAllAuction() 
    { 
     return Query(); 
    } 

    // GET tables/Auction/48D68C86-6EA6-4C25-AA33-223FC9A27959 
    public SingleResult<Auction> GetAuction(string id) 
    { 
     return Lookup(id); 
    } 

    // PATCH tables/Auction/48D68C86-6EA6-4C25-AA33-223FC9A27959 
    public Task<Auction> PatchAuction(string id, Delta<Auction> patch) 
    { 
     return UpdateAsync(id, patch); 
    } 

    // POST tables/Auction 
    public async Task<IHttpActionResult> PostAuction(Auction item) 
    { 
     Auction current = await InsertAsync(item); 
     return CreatedAtRoute("Tables", new { id = current.Id }, current); 
    } 

    // DELETE tables/Auction/48D68C86-6EA6-4C25-AA33-223FC9A27959 
    public Task DeleteAuction(string id) 
    { 
     return DeleteAsync(id); 
    } 
} 

Mit meiner generischen Anwendung kann ich jede DbContext so wenden Sie sogar FakeDbContexts, um zu vermeiden SqlConnection oder Cloud-Verbindung wie Azure anwenden könnten, die die, die ich in diesem Beispiel verwendet werden.

All dies zwei Bibliothek sind auf meinem Backend-Projekt, jetzt werde ich Ihnen mein Testprojekt, um Unit-Test zeigen eine TableController

public abstract class ControllerTestBase<TController, TModel, TDbContext> where TController : BaseController<TModel, TDbContext>, new() 
                      where TModel : class, ITableData 
                      where TDbContext: DbContext, new() 
{ 
    protected readonly TController Controller; 

    protected ControllerTestBase() 
    { 
     Controller = new TController(); 
     var context = new TDbContext(); 
     Controller.SetDomainManager(new EntityDomainManager<TModel>(context, new HttpRequestMessage())); 
    } 
} 

Ok dank dieser abstrakten Klasse Sie die initialize Setup unterdrücken können aus Die Testbibliothek, da jedes Mal, wenn Sie einen Test ausführen, wird der generische Testkonstruktor aufgerufen, alle notwendigen Requirements eingerichtet und damit ArgumentNullExceptions und InvalidOperationExceptions wie häufiges Problem für Unit Testing Tablecontroller zu vermeiden, da nicht ganz intuitiv als ApiController initialisieren.

Schließlich, wenn Sie dies ändern, dann können Sie einen Test wie folgt ausführen:

[TestClass] 
public class AuctionControllerTest : ControllerTestBase<AuctionController, Auction, MobileServiceContext> 
{ 
    [TestMethod] 
    public void Fetch_All_Existing_Items() 
    { 
     Assert.AreEqual(1, Controller.GetAllAuction().ToList().Count); 
    } 
} 

dank meiner generische Anwendung können Sie jetzt diesen Code als Beispiel verwenden, um Ihre TableControllers zu sein gelten und auch, wenn Sie folgen Das Interface Separation Principle, mit dem Sie FakeDbContext auf Ihre Controller anwenden können.

Für diejenigen, die mir dankten, öffnete ich meine Meinung mit dieser Lösung zu kommen !!!

+0

danke für den Änderungsvorschlag mann !! –

2

Ja. Es ist möglich, aber Sie Code ist nicht testbar. Hier sind die Schritte für Sie

  1. einen Weg finden, Ihre depedencies injizieren MobileServiceContext und DomainManager
  2. Sie müssen einrichten Kontexte und Anfragen usw., wie in in den folgenden Code dargestellt.

(-Code wird davon ausgegangen Sie verwenden Moq)

public class ControllerUnitTestBase<T> where T: Controller  
{ 
    private Action<RouteCollection> _routeRegistrar; 
    private Mock<HttpRequestBase> _mockRequest; 

    protected virtual Action<RouteCollection> RouteRegistrar 
    { 
     get { return _routeRegistrar ?? DefaultRouteRegistrar; } 
     set { _routeRegistrar = value; } 
    } 

    protected Mock<HttpRequestBase> MockRequest 
    { 
     get 
     { 
      if (_mockRequest == null) 
      { 
       _mockRequest = new Mock<HttpRequestBase>(); 
      } 

      return _mockRequest; 
     } 
    } 

    public abstract T TargetController { get; } 

    protected void TargetSetup() 
    { 
     var routes = new RouteCollection(); 
     RouteRegistrar(routes); 

     var responseMock = new Mock<HttpResponseBase>(); 
     responseMock.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns((string url) => url); 

     var contextMock = new Mock<HttpContextBase>(); 
     contextMock.SetupGet(x => x.Request).Returns(MockRequest.Object); 
     contextMock.SetupGet(x => x.Response).Returns(responseMock.Object); 
     contextMock.SetupGet(x => x.Session).Returns(Mock<HttpSessionStateBase>().Object); 

     TargetController.ControllerContext = new ControllerContext(contextMock.Object, new RouteData(), TargetController); 
     TargetController.Url = new UrlHelper(new RequestContext(contextMock.Object, new RouteData()), routes); 
    } 

    protected void DefaultRouteRegistrar(RouteCollection routes) 
    { 
     routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

     routes.MapRoute(
      name: "Default", 
      url: "{controller}/{action}/{id}", 
      defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }); 
    } 
} 

Vererben von diesem Code und stellen Sie sicher, dass Sie rufen TargetSetup() vor der Testdurchführung (möglicherweise in Testinitialisierung (Setup). Und Sie sind gut zu gehen, wie in:

[TestClass] 
    public class AuctionControllerTests: TestControllerBase<AuctionController> 
    { 

    public AuctionController TargetController { 
     get {return new AuctionController();//inject your mocked dependencies}} 

    [TestInitialize] 
    public void SetUp() 
    { 
     TargetSetup() 
    } 
    } 
+0

Tut mir leid, aber Ihr Code hat Fehler und um ehrlich zu sein weiß ich nicht, wie man sie löst. ‚UrlHelper‘ enthält keinen Konstruktor, der zwei Argumente übernimmt, Der Name ‚Target‘ existiert nicht im aktuellen Kontext, Der Name ‚UrlParameter‘ existiert nicht im aktuellen Kontext , was ich für seine gesucht um einen Integrationstest zu machen, möchte ich nicht, dass Ergebnisse gespottet werden !!! –

+0

Ja. Ich habe das Ziel festgelegt. UrlHelper und UrlParameter fügen jedoch die Namespaces mit System.Web hinzu. mit System.Web.Mvc; mit System.Web.Routing; Sie müssen auf die MVC/Web-Baugruppen in Ihrem Test-Projekt verweisen –

+0

Danke Mann !!! es funktionierte und gab mir auch eine Vorstellung davon, wie ich meine eigene generische Version entwickeln konnte, da ich in der Lage war, den Underhood eines Tablecontrollers oder Apicontrollers zu verstehen. –