। নেট কোর ইউনিট পরীক্ষা - মক আইওপশনস <টি>>


137

আমার মনে হচ্ছে আমি এখানে সত্যিই সুস্পষ্ট কিছু মিস করছি। আমার কাছে ক্লাস রয়েছে যার জন্য। নেট কোর আইওপশন প্যাটার্ন (?) ব্যবহার করে বিকল্পগুলির ইনজেকশন প্রয়োজন। আমি যখন ক্লাসের ইউনিট পরীক্ষায় যাই তখন আমি ক্লাসের কার্যকারিতাটি বৈধতা দেওয়ার বিকল্পগুলির বিভিন্ন সংস্করণে উপহাস করতে চাই। কেউ কি জানেন যে কীভাবে সঠিকভাবে স্টার্টআপ ক্লাসের বাইরে আইওপশনগুলি উপহাস / ইনস্ট্যান্টিয়েট / পপুলেট করা যায়?

আমি যে ক্লাসগুলির সাথে কাজ করছি তার কয়েকটি নমুনা এখানে দেওয়া হল:

সেটিংস / বিকল্প মডেল

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace OptionsSample.Models
{
    public class SampleOptions
    {
        public string FirstSetting { get; set; }
        public int SecondSetting { get; set; }
    }
}

সেটিংস ব্যবহার করে যা পরীক্ষা করা ক্লাস:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using OptionsSample.Models
using System.Net.Http;
using Microsoft.Extensions.Options;
using System.IO;
using Microsoft.AspNetCore.Http;
using System.Xml.Linq;
using Newtonsoft.Json;
using System.Dynamic;
using Microsoft.Extensions.Logging;

namespace OptionsSample.Repositories
{
    public class SampleRepo : ISampleRepo
    {
        private SampleOptions _options;
        private ILogger<AzureStorageQueuePassthru> _logger;

        public SampleRepo(IOptions<SampleOptions> options)
        {
            _options = options.Value;
        }

        public async Task Get()
        {
        }
    }
}

অন্যান্য শ্রেণি থেকে পৃথক সমাবেশে ইউনিট পরীক্ষা:

using OptionsSample.Repositories;
using OptionsSample.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;

namespace OptionsSample.Repositories.Tests
{
    public class SampleRepoTests
    {
        private IOptions<SampleOptions> _options;
        private SampleRepo _sampleRepo;


        public SampleRepoTests()
        {
            //Not sure how to populate IOptions<SampleOptions> here
            _options = options;

            _sampleRepo = new SampleRepo(_options);
        }
    }
}

1
আপনি যে ব্লকটিকে উপহাস করার চেষ্টা করছেন তার একটি ছোট কোড উদাহরণ সরবরাহ করতে পারেন? ধন্যবাদ!
এজে এক্স।

আপনি কি বিদ্রূপের অর্থ বিভ্রান্ত করছেন? আপনি একটি ইন্টারফেস উপহাস করে এবং একটি নির্দিষ্ট মান ফেরত দেওয়ার জন্য এটি কনফিগার করেন। আপনি যে ক্লাসটি চান তা ফেরত দেওয়ার জন্য IOptions<T>আপনাকে কেবল উপহাস Valueকরতে হবে
Tseng

উত্তর:


253

আপনাকে ম্যানুয়ালি একটি IOptions<SampleOptions>অবজেক্ট তৈরি এবং পপুলেট করা দরকার । আপনি Microsoft.Extensions.Options.Optionsসহায়ক শ্রেণীর মাধ্যমে এটি করতে পারেন । উদাহরণ স্বরূপ:

IOptions<SampleOptions> someOptions = Options.Create<SampleOptions>(new SampleOptions());

আপনি এটি কিছুটা সহজ করতে পারেন:

var someOptions = Options.Create(new SampleOptions());

স্পষ্টতই এটি যেমনটি তেমন কার্যকর নয়। আপনাকে আসলে একটি নমুনা বিভাগ তৈরি করতে এবং পপুলেট করতে হবে এবং এটি তৈরি পদ্ধতিতে পাস করতে হবে।


আমি সমস্ত অতিরিক্ত উত্তরগুলির প্রশংসা করি যা মক ইত্যাদি ব্যবহার করতে পারে তা দেখায়, তবে এই উত্তরটি এত সহজ যে এটি অবশ্যই আমি ব্যবহার করছি। এবং এটি দুর্দান্ত কাজ করে!
গ্রেহেমসড

দুর্দান্ত উত্তর। মজাদার কাঠামোর উপর নির্ভর করা এত সহজ।
ক্রিস লরেন্স

2
ধন্যবাদ। আমি new OptionsWrapper<SampleOptions>(new SampleOptions());সর্বত্র লিখতে গিয়ে ক্লান্ত হয়ে পড়েছিলাম
ব্রিটিশ ডেভেলপার

59

আপনি যদি মন্তব্যে @ টিএসএং দ্বারা নির্দেশিত মজাদার ফ্রেমওয়ার্কটি ব্যবহার করতে চান তবে আপনার প্রজেক্ট.জসন ফাইলে আপনাকে নিম্নলিখিত নির্ভরতা যুক্ত করতে হবে।

   "Moq": "4.6.38-alpha",

নির্ভরতা পুনরুদ্ধার হয়ে গেলে, এমওকিউ ফ্রেমওয়ার্ক ব্যবহার করা স্যাম্পলঅ্যাপশন শ্রেণীর উদাহরণ তৈরি করার মতো সহজ এবং তারপরে উল্লিখিত হিসাবে এটি মানকে নির্ধারিত করে।

এটি দেখতে একটি কোডের আউটলাইন।

SampleOptions app = new SampleOptions(){Title="New Website Title Mocked"}; // Sample property
// Make sure you include using Moq;
var mock = new Mock<IOptions<SampleOptions>>();
// We need to set the Value of IOptions to be the SampleOptions Class
mock.Setup(ap => ap.Value).Returns(app);

মক সেটআপ হয়ে গেলে আপনি এখন মক অবজেক্টটি কনট্রাক্টরের কাছে পাস করতে পারেন

SampleRepo sr = new SampleRepo(mock.Object);   

আছে HTH।

এফওয়াইআই আমার কাছে একটি গিট সংগ্রহস্থল রয়েছে যা গিথুব / প্যাটভিন 80 এ এই 2 পদ্ধতির রূপরেখা দেয়


এটি গ্রহণযোগ্য উত্তর হওয়া উচিত, এটি নিখুঁতভাবে কাজ করে।
alessandrocb

সত্যই কামনা করুন এটি আমার জন্য কাজ করেছে, তবে এটি করে না :( Moq 4.13.1
কানপেকি

21

আপনি মোটেও MOQ ব্যবহার এড়াতে পারবেন। আপনার পরীক্ষাগুলিতে .json কনফিগারেশন ফাইল ব্যবহার করুন। অনেক পরীক্ষার শ্রেণীর ফাইলের জন্য একটি ফাইল। ConfigurationBuilderএই ক্ষেত্রে ব্যবহার করা ভাল হবে ।

Appsetting.json উদাহরণ

{
    "someService" {
        "someProp": "someValue
    }
}

সেটিংস ম্যাপিং ক্লাসের উদাহরণ:

public class SomeServiceConfiguration
{
     public string SomeProp { get; set; }
}

পরীক্ষার জন্য প্রয়োজনীয় সেবার উদাহরণ:

public class SomeService
{
    public SomeService(IOptions<SomeServiceConfiguration> config)
    {
        _config = config ?? throw new ArgumentNullException(nameof(_config));
    }
}

ননিট পরীক্ষার ক্লাস:

[TestFixture]
public class SomeServiceTests
{

    private IOptions<SomeServiceConfiguration> _config;
    private SomeService _service;

    [OneTimeSetUp]
    public void GlobalPrepare()
    {
         var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", false)
            .Build();

        _config = Options.Create(configuration.GetSection("someService").Get<SomeServiceConfiguration>());
    }

    [SetUp]
    public void PerTestPrepare()
    {
        _service = new SomeService(_config);
    }
}

এটি আমার জন্য সুন্দরভাবে কাজ করেছে, চিয়ার্স! এমন কিছুর জন্য মাক ব্যবহার করতে চাননি যা কনফিগারেশন সেটিংস সহ আমার নিজস্ব বিকল্পগুলি চেষ্টা করতে চায় না।
হ্যারি

3
দুর্দান্ত কাজ করে তবে তথ্যের গুরুত্বপূর্ণ অনুপস্থিত অংশটি হ'ল আপনাকে মাইক্রোসফ্ট.এক্সটেনশনগুলি C কনফিগারেশন.বাইন্ডার নুগেট প্যাকেজ অন্তর্ভুক্ত করতে হবে, অন্যথায় আপনি "<< হোমসোভারসিসি কনফিগারেশন> পান" এক্সটেনশন পদ্ধতিটি উপলভ্য হন না।
गति

এটি কাজ করার জন্য আমাকে ডটনেট অ্যাড প্যাকেজ চালাতে হয়েছিল মাইক্রোসফ্ট। দুর্দান্ত উত্তর!
লিওনার্দো ওয়াইল্ড

1
ডাইরেক্টরি.গেটক্র্যান্ট ডিরেক্টরী () বিন ফাইলটির বিষয়বস্তু ফিরিয়ে দিচ্ছিল বলে আমাকে বিন ফাইলটিতে ফাইলটি ব্যবহার করতে অ্যাপসেটেটিংস.জসন ফাইলের বৈশিষ্ট্যগুলিও পরিবর্তন করতে হয়েছিল। Appsettings.json এর "কপিরাইট টু আউটপুট ডিরেক্টরিতে", আমি "নতুন হলে কপি করুন" এ মান সেট করেছিলাম।
বিপিজেড

14

প্রদত্ত শ্রেণি Personযা PersonSettingsনিম্নলিখিত হিসাবে নির্ভর করে :

public class PersonSettings
{
    public string Name;
}

public class Person
{
    PersonSettings _settings;

    public Person(IOptions<PersonSettings> settings)
    {
        _settings = settings.Value;
    }

    public string Name => _settings.Name;
}

IOptions<PersonSettings>উপহাস করা যায় এবং Personনিম্নলিখিত হিসাবে পরীক্ষা করা যেতে পারে:

[TestFixture]
public class Test
{
    ServiceProvider _provider;

    [OneTimeSetUp]
    public void Setup()
    {
        var services = new ServiceCollection();
        // mock PersonSettings
        services.AddTransient<IOptions<PersonSettings>>(
            provider => Options.Create<PersonSettings>(new PersonSettings
            {
                Name = "Matt"
            }));
        _provider = services.BuildServiceProvider();
    }

    [Test]
    public void TestName()
    {
        IOptions<PersonSettings> options = _provider.GetService<IOptions<PersonSettings>>();
        Assert.IsNotNull(options, "options could not be created");

        Person person = new Person(options);
        Assert.IsTrue(person.Name == "Matt", "person is not Matt");    
    }
}

এটি স্পষ্টভাবে সিটরের কাছে IOptions<PersonSettings>প্রবেশের Personপরিবর্তে ইনজেক্ট করতে , এই কোডটি ব্যবহার করুন:

[TestFixture]
public class Test
{
    ServiceProvider _provider;

    [OneTimeSetUp]
    public void Setup()
    {
        var services = new ServiceCollection();
        services.AddTransient<IOptions<PersonSettings>>(
            provider => Options.Create<PersonSettings>(new PersonSettings
            {
                Name = "Matt"
            }));
        services.AddTransient<Person>();
        _provider = services.BuildServiceProvider();
    }

    [Test]
    public void TestName()
    {
        Person person = _provider.GetService<Person>();
        Assert.IsNotNull(person, "person could not be created");

        Assert.IsTrue(person.Name == "Matt", "person is not Matt");
    }
}

আপনি দরকারী কিছু পরীক্ষা করছেন না। আমার মাইক্রোসফ্ট ডিআই এর ফ্রেমওয়ার্কটি ইতিমধ্যে ইউনিট পরীক্ষিত। যেহেতু এটি দাঁড়িয়েছে এটি সত্যই একটি ইন্টিগ্রেশন পরীক্ষা (তৃতীয় পক্ষের কাঠামোর সাথে সংহতকরণ)।
এরিক ফিলিপস

2
@ এরিক ফিলিপস আমার কোডটি দেখায় যে কীভাবে আইওপশনগুলি উপহাস করা যায় <টি> ওপির অনুরোধ অনুসারে। আমি সম্মত হই যে এটি নিজের মধ্যে দরকারী কিছু পরীক্ষা করে না, তবে এটি অন্য কোনও কিছুর জন্য দরকারী হতে পারে useful
ফ্র্যাঙ্ক রিম

13

আপনি সর্বদা অপশনগুলির মাধ্যমে আপনার বিকল্পগুলি তৈরি করতে পারেন re AutoMocker.CreateInstance <> () ব্যবহার করে ম্যানুয়ালি প্যারামিটারগুলি পাস না করে দৃষ্টান্ত তৈরি করা সহজ করে তোলে

আমার মনে হয় যে আপনি যে আচরণটি অর্জন করতে চান তার আচরণ পুনরুত্পাদন করতে সক্ষম হওয়ার জন্য আপনি স্যাম্পেলরেপোকে কিছুটা পরিবর্তন করেছি।

public class SampleRepoTests
{
    private readonly AutoMocker _mocker = new AutoMocker();
    private readonly ISampleRepo _sampleRepo;

    private readonly IOptions<SampleOptions> _options = Options.Create(new SampleOptions()
        {FirstSetting = "firstSetting"});

    public SampleRepoTests()
    {
        _mocker.Use(_options);
        _sampleRepo = _mocker.CreateInstance<SampleRepo>();
    }

    [Fact]
    public void Test_Options_Injected()
    {
        var firstSetting = _sampleRepo.GetFirstSetting();
        Assert.True(firstSetting == "firstSetting");
    }
}

public class SampleRepo : ISampleRepo
{
    private SampleOptions _options;

    public SampleRepo(IOptions<SampleOptions> options)
    {
        _options = options.Value;
    }

    public string GetFirstSetting()
    {
        return _options.FirstSetting;
    }
}

public interface ISampleRepo
{
    string GetFirstSetting();
}

public class SampleOptions
{
    public string FirstSetting { get; set; }
}

8

এখানে আরও একটি সহজ উপায় যার জন্য মোক প্রয়োজন হয় না, তবে এর পরিবর্তে বিকল্পশক্তি ব্যবহার করে:

var myAppSettingsOptions = new MyAppSettingsOptions();
appSettingsOptions.MyObjects = new MyObject[]{new MyObject(){MyProp1 = "one", MyProp2 = "two", }};
var optionsWrapper = new OptionsWrapper<MyAppSettingsOptions>(myAppSettingsOptions );
var myClassToTest = new MyClassToTest(optionsWrapper);

2

আমার সিস্টেম এবং ইন্টিগ্রেশন পরীক্ষার জন্য আমি পরীক্ষার প্রকল্পের ভিতরে আমার কনফিগারেশন ফাইলের একটি অনুলিপি / লিঙ্ক রাখতে পছন্দ করি। এবং তারপরে অপশনগুলি পেতে কনফিগারেশনবিল্ডারটি ব্যবহার করি।

using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace SomeProject.Test
{
public static class TestEnvironment
{
    private static object configLock = new object();

    public static ServiceProvider ServiceProvider { get; private set; }
    public static T GetOption<T>()
    {
        lock (configLock)
        {
            if (ServiceProvider != null) return (T)ServiceProvider.GetServices(typeof(T)).First();

            var builder = new ConfigurationBuilder()
                .AddJsonFile("config/appsettings.json", optional: false, reloadOnChange: true)
                .AddEnvironmentVariables();
            var configuration = builder.Build();
            var services = new ServiceCollection();
            services.AddOptions();

            services.Configure<ProductOptions>(configuration.GetSection("Products"));
            services.Configure<MonitoringOptions>(configuration.GetSection("Monitoring"));
            services.Configure<WcfServiceOptions>(configuration.GetSection("Services"));
            ServiceProvider = services.BuildServiceProvider();
            return (T)ServiceProvider.GetServices(typeof(T)).First();
        }
    }
}
}

এইভাবে আমি আমার টেস্টপ্রজেক্টের অভ্যন্তরে কনফিগারটি ব্যবহার করতে পারি। ইউনিট পরীক্ষার জন্য আমি বর্ণিত পটভিন 80 এর মতো এমওকিউ ব্যবহার করতে পছন্দ করি।


1

আলেহার সাথে সম্মত হন যে একটি টেস্টসেটেটিংস.জসন কনফিগারেশন ফাইল ব্যবহার করা সম্ভবত আরও ভাল। এবং তারপরে আইওশনটি ইনজেকশনের পরিবর্তে আপনি কেবল আপনার শ্রেণীর নির্মাত্রে আসল নমুনা অপশনগুলি ইনজেক্ট করতে পারেন, যখন ইউনিট শ্রেণি পরীক্ষা করে, আপনি কেবল পরীক্ষার শ্রেণীর কনস্ট্রাক্টরে নিম্নোক্তভাবে বা আবার পরীক্ষা করতে পারেন:

   var builder = new ConfigurationBuilder()
  .AddJsonFile("testSettings.json", true, true)
  .AddEnvironmentVariables();

  var configurationRoot = builder.Build();
  configurationRoot.GetSection("SampleRepo").Bind(_sampleRepo);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.