2017-03-01 8 views
13

मैं कुछ कक्षाओं का परीक्षण करना चाहता हूं जो एएसपी.नेट वेब एपीआई परियोजना का हिस्सा हैं। मुझे टेस्टसेवर के माध्यम से अनुरोध-प्रतिक्रिया एकीकरण परीक्षण की आवश्यकता नहीं है (हालांकि वे अच्छे हैं) लेकिन मैं अपने परीक्षणों को यथासंभव "वास्तविक चीज़" के करीब रखना चाहता हूं। तो मैं स्टार्टअप में जोड़े गए सेवाओं का उपयोग करके अपनी कक्षाओं को हल करना चाहता हूं लेकिन परीक्षण के आधार पर उनमें से कुछ को स्टब्स/मैक्स द्वारा बदलना (कुछ परीक्षणों को मोक्स की जरूरत है, अन्य - नहीं)।मैं एएसपी.NET कोर परीक्षणों में सेवाओं को कैसे रोक सकता/सकती हूं

अच्छे पुराने दिनों में करना वास्तव में आसान था जब एएसपी.नेट में आंतरिक निर्भरता इंजेक्शन ढांचा नहीं था। तो मैं सिर्फ एक वर्ग को कॉल करता हूं जो सभी निर्भरताओं को एक कंटेनर में पंजीकृत करता है, फिर प्रत्येक परीक्षण के लिए बाल कंटेनर बनाते हैं, कुछ निर्भरताओं को मोक्स में बदलते हैं और यही वह है।

var host = A.Fake<IHostingEnvironment>(); 
    var startup = new Startup(host); 
    var services = new ServiceCollection(); 
    //Add stubs here 
    startup.ConfigureServices(services); 
    var provider = services.BuildServiceProvider(); 
    provider.GetService<IClientsHandler>(); 

यह काम करने के लिए लगता है, लेकिन मैं हर परीक्षा के लिए पूरे स्टार्टअप बुनियादी ढांचा तैयार करने के लिए नहीं करना चाहती:

मैं कुछ इस तरह की कोशिश की। मैं इसे एक बार बनाना चाहता हूं और फिर प्रत्येक परीक्षण के लिए "बाल कंटेनर" या "बाल स्कोप" बनाना चाहता हूं। क्या यह संभव है? असल में मैं स्टार्टअप के बाहर सेवाओं को संशोधित करने का एक तरीका ढूंढ रहा हूं।

उत्तर

2

यह सभी documentation में अच्छी तरह से कवर किया गया है।

एकीकरण परीक्षण के लिए, आप लाइव स्टार्टअप होने की TestServer वर्ग का उपयोग करें और यह एक Startup वर्ग देना (नहीं है, यह भी साथ StartupIntegrationTest या स्टार्टअप हो सकता है Configure{Envrionment Name here}/ConfigureServices{Envrionment Name here} विधि।

var server = new TestServer(new WebHostBuilder() 
    .UseStartup<Startup>() 
    // this would cause it to use StartupIntegrationTest class or ConfigureServicesIntegrationTest/ConfigureIntegrationTest methods (if existing) 
    // rather than Startup, ConfigureServices and Configure 
    .UseEnvironment("IntegrationTest")); 

तक पहुंचने के लिए सेवा प्रदाता, कर

var server = new TestServer(new WebHostBuilder() 
    .UseStartup<Startup>() 
    .UseEnvironment("IntegrationTest")); 
var controller = server.Host.Services.GetService<MyService>(); 

ईकाई परीक्षण के लिए आप IServiceCollection/IServiceProvider सब पर उपयोग नहीं करना चाहिए, बस इंटरफेस नकली और उन्हें इंजेक्षन।

+1

लेकिन मैं मैन्युअल रूप से मॉक किए गए इंटरफेस इंजेक्ट नहीं करना चाहता हूं। मैं सेवाओं का उपयोग कर कक्षा को हल करना चाहता हूं और मैं कक्षा को हल करने से पहले कुछ इंटरफेस के लिए मैक्स निर्दिष्ट करना चाहता हूं। – SiberianGuy

+0

पूरा जवाब पढ़ें। अंतिम अनुच्छेद केवल यूनिट परीक्षण के लिए है, अधिकांश उत्तर एकीकरण परीक्षण करने के बारे में है और उन्हें कैसे किया जाना चाहिए। यही टेस्टसेवर है और इसके लिए स्टार्टअप का उपयोग किया जाता है। हालांकि आपको अनुरोध का उपयोग करने की आवश्यकता नहीं है, लेकिन जैसा कि दूसरे कोड उदाहरण में उल्लेख किया गया है, आप केवल परीक्षण सर्वर उदाहरण – Tseng

+0

से IServiceProvider तक पहुंच सकते हैं, तो आप मानते हैं कि हमें प्रत्येक परीक्षण के लिए एक नया टेस्ट सर्वर बनाना चाहिए? मैं सिर्फ यह नहीं देखता कि मैं एक टेस्टसेवर कैसे बना सकता हूं और प्रत्येक परीक्षण के लिए निर्भरता बदल सकता हूं (कुछ परीक्षणों के लिए मुझे मोक्स चाहिए, दूसरों के लिए मैं नहीं करता)। – SiberianGuy

3

कस्टम अनुरोध IHttpControllerActivator बनाकर अपने एचटीपी कॉन्फ़िगरेशन को कॉन्फ़िगर करते समय प्रत्येक अनुरोध के लिए बाल स्कोप बनाना।

यह Owin के लिए है, लेकिन नेट कोर को बदलने बहुत सरल होना चाहिए: https://gist.github.com/jt000/eef096a2341471856e8a86d06aaec887

महत्वपूर्ण भागों है कि क्षेत्र में एक स्कोप & नियंत्रक बनाने के लिए कर रहे हैं ...

var scope = _provider.CreateScope(); 
request.RegisterForDispose(scope); 

var controller = scope.ServiceProvider.GetService(controllerType) as IHttpController; 

। ..और डिफ़ॉल्ट IHttpControllerActivator ...

config.Services.Replace(typeof (IHttpControllerActivator), new ServiceProviderControllerActivator(parentActivator, provider)); 

अब आप अपने contr जोड़ सकते हैं अधिलेखित ollers scoped निर्भरता इंजेक्शन के साथ IServiceProvider के माध्यम से बनाया जाना ...

services.AddScoped<ValuesController>((sp) => new ValuesController(sp.GetService<ISomeCustomService>())); 

अपने इकाई परीक्षण के भीतर अपने ValuesController परीक्षण करने के लिए, मैं आपकी सेवा इंटरफेस में तरीकों बाहर उपहास करने के लिए Moq ढांचे की तरह कुछ का उपयोग कर सुझाव है।उदाहरण के लिए:

var someCustomService = Mock.Of<ISomeCustomService>(s => s.DoSomething() == 3); 
var sut = new ValuesController(someCustomService); 

var result = sut.Get(); 

Assert.AreEqual(result, new [] { 3 }); 
+0

मेरे पास इसे देखने के लिए समय नहीं था लेकिन यह आशाजनक लग रहा है। धन्यवाद! – SiberianGuy

1

बस मामले में आप (मैं उन्हें इस मामले में एकीकरण परीक्षणों कहेंगे) अपने xUnit इकाई परीक्षण के लिए एक ही Web API Core नियंत्रकों और DI बुनियादी सुविधाओं का उपयोग करना चाहेंगे, मैं ले जाने के लिए प्रस्ताव होगा TestServer और HttpClientxUnitIClassFixture लागू करने वाले बेस क्लास के संदर्भ।

इस मामले में आप सभी सेवाओं के साथ API और DI आप में विन्यस्त परीक्षण अपने वास्तविक Web API Core:

public class TestServerDependent : IClassFixture<TestServerFixture> 
{ 
    private readonly TestServerFixture _fixture; 
    public TestServer TestServer => _fixture.Server; 
    public HttpClient Client => _fixture.Client; 

    public TestServerDependent(TestServerFixture fixture) 
    { 
     _fixture = fixture; 
    } 

    protected TService GetService<TService>() 
     where TService : class 
    { 
     return _fixture.GetService<TService>(); 
    } 
} 

public class TestServerFixture : IDisposable 
{ 
    public TestServer Server { get; } 
    public HttpClient Client { get; } 

    public TestServerFixture() 
    { 
     // UseStaticRegistration is needed to workaround AutoMapper double initialization. Remove if you don't use AutoMapper. 
     ServiceCollectionExtensions.UseStaticRegistration = false; 

     var hostBuilder = new WebHostBuilder() 
      .UseEnvironment("Testing") 
      .UseStartup<Startup>(); 

     Server = new TestServer(hostBuilder); 
     Client = Server.CreateClient(); 
    } 

    public void Dispose() 
    { 
     Server.Dispose(); 
     Client.Dispose(); 
    } 

    public TService GetService<TService>() 
     where TService : class 
    { 
     return Server?.Host?.Services?.GetService(typeof(TService)) as TService; 
    } 
} 

तो फिर तुम सिर्फ इस वर्ग से निकाले जाते हैं नियंत्रक कार्रवाई इस तरह से परीक्षण करने के लिए कर सकते हैं:

public class ValueControllerTests : TestServerDependent 
{ 
    public ValueControllerTests(TestServerFixture fixture) 
     : base(fixture) 
    { 
    } 

    [Fact] 
    public void Returns_Ok_Response_When_Requested() 
    { 
     var responseMessage = Client.GetAsync("/api/value").Result; 
     Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode); 
    } 
} 

public class MyServiceTests : TestServerDependent 
{ 
    public MyServiceTests(TestServerFixture fixture) 
     : base(fixture) 
    { 
    } 

    [Fact] 
    public void ReturnsDataWhenServiceInjected() 
    { 
     var service = GetService<IMyService>(); 
     Assert.NotNull(service); 

     var data = service.GetData(); 
     Assert.NotNull(data); 
    } 
} 
:

इसके अलावा, आप DI सेवाओं का परीक्षण कर सकते हैं

संबंधित मुद्दे