ASP.NET Web API - قسمت اول
پیشنیاز
- نقشه راه «آزمون واحد در دات نت»
- مطلب «طراحی و پیاده سازی ServiceLayer به همراه خودکارسازی Business Validationها»
در این مطلب قصد داریم تست ServiceLayer را به جای تست درون حافظهای که با ابزارهای Mocking در قالب Unit Testing انجام میگیرد، به کمک یک دیتابیس واقعی سبک وزن در قالب Integration Testing انجام دهیم.
قدم اول
یک پروژه تست را ایجاد کنید؛ بهتر است برای نظم دهی به ساختار Solution، پروژههای تست را در پوشه ای به نام Tests نگهداری کنید.
قدم دوم
بستههای نیوگت زیر را نصب کنید:
PM> install-package NUnit PM> install-package Shouldly PM> install-package EntityFramework PM> install-package FakeHttpContext
قدم سوم
نسخه دیتابیس انتخابی برای تست خودکار، LocalDB می باشد. لازم است در ابتدای اجرای تستها دیتابیس مربوط به Integration Test ایجاد شده و بعد از اتمام نیز دیتابیس مورد نظر حذف شود؛ برای این منظور از کلاس TestSetup استفاده خواهیم کرد.
[SetUpFixture] public class TestSetup { [OneTimeSetUp] public void SetUpDatabase() { DestroyDatabase(); CreateDatabase(); } [OneTimeTearDown] public void TearDownDatabase() { DestroyDatabase(); } //... }
با توجه به اینکه کلاس TestSetup با [SetUpFixture] تزئین شده است، Nunit قبل از اجرای تستها سراغ این کلاس آمده و متد SetUpDatebase را به دلیل تزئین شدن با [OneTimeSetUp]، قبل از اجرای تستها و متد TearDownDatabase را بدلیل تزئین شدن با [OneTimeTearDown] بعد از اجرای تمام تستها، اجرا خواهد کرد.
متد CreateDatabase
private static void CreateDatabase() { ExecuteSqlCommand(Master, string.Format(SqlResource.DatabaseScript, FileName)); //Use T-Sql Scripts For Create Database //ExecuteSqlCommand(MyAppTest, SqlResources.V1_0_0); var migration = new MigrateDatabaseToLatestVersion<ApplicationDbContext, DataLayer.Migrations.Configuration>(); migration.InitializeDatabase(new ApplicationDbContext()); } private static SqlConnectionStringBuilder Master => new SqlConnectionStringBuilder { DataSource = @"(LocalDB)\MSSQLLocalDB", InitialCatalog = "master", IntegratedSecurity = true }; private static string FileName => Path.Combine( Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location), "MyAppTest.mdf");
برای مدیریت محل ذخیره سازی فایلهای دیتابیس، ابتدا دستورات ایجاد «دیتابیس تست» را برروی دیتابیس master اجرا میکنیم و در ادامه برای ساخت جداول از مکانیزم Migration خود EF استفاده شده است.
لازم است رشته اتصال به این دیتابیس ایجاد شده را در فایل App.config پروژه تست قرار دهید:
<connectionStrings> <add name="DefaultConnection" providerName="System.Data.SqlClient" connectionString="Data Source=(LocalDB)\MSSQLLocalDb;Initial Catalog=MyAppTest;Integrated Security=True;" /> </connectionStrings>
متد DestroyDatabase
private static void DestroyDatabase() { var fileNames = ExecuteSqlQuery(Master, SqlResource.SelecDatabaseFileNames, row => (string)row["physical_name"]); if (!fileNames.Any()) return; ExecuteSqlCommand(Master, SqlResource.DetachDatabase); fileNames.ForEach(File.Delete); }
در این متد ابتدا آدرس فایلهای مرتبط با «دیتابیس تست» واکشی شده و در ادامه دستورات Detach دیتابیس انجام شده و فایلهای مرتبط حذف خواهند شد. فایلهای دیتابیس در مسیری شبیه به آدرس نشان داده شدهی در شکل زیر ذخیره خواهند شد.
قدم چهارم
برای جلوگیری از تداخل بین تستها لازم است تک تک تستها از هم ایزوله باشند؛ یکی از راه حلهای موجود، استفاده از تراکنشها میباشد. برای این منظور امکان AutoRollback را به صورت خودکار به متدهای تست با استفاده از Attribute زیر اعمال خواهیم کرد:
public class AutoRollbackAttribute : Attribute, ITestAction { private TransactionScope _scope; public void BeforeTest(ITest test) { _scope = new TransactionScope(TransactionScopeOption.RequiresNew,new TransactionOptions {IsolationLevel = IsolationLevel.Snapshot}); } public void AfterTest(ITest test) { _scope?.Dispose(); _scope = null; } public ActionTargets Targets => ActionTargets.Test; }
متدهای BeforTest و AfterTest به ترتیب قبل و بعد از اجرای متدهای تست تزئین شده با این Attribute اجرا خواهند شد.
در مواقعی هم که به HttpConext نیاز دارید، میتوانید از کتابخانه FakeHttpContext بهره ببرید. برای این مورد هم میتوان Attributeای را به مانند AutoRollback در نظر گرفت.
public class HttpContextAttribute:Attribute,ITestAction { private FakeHttpContext.FakeHttpContext _httpContext; public void BeforeTest(ITest test) { _httpContext = new FakeHttpContext.FakeHttpContext(); } public void AfterTest(ITest test) { _httpContext?.Dispose(); _httpContext = null; } public ActionTargets Targets => ActionTargets.Test; }
کاری که FakeHttpContext انجام میدهد، مقدار دهی HttpContext.Current با یک پیاده سازی ساختگی میباشد.
قدم پنجم
به عنوان مثال اگر بخواهیم برای سرویس «گروه کاربری»، Integration Test بنویسیم، به شکل زیر عمل خواهیم کرد:
namespace MyApp.IntegrationTests.ServiceLayer { [TestFixture] [AutoRollback] [HttpContext] public class RoleServiceTests { private IRoleApplicationService _roleService; [SetUp] public void Init() { } [TearDown] public void Clean() { } [OneTimeSetUp] public void SetUp() { _roleService = IoC.Resolve<IRoleApplicationService>(); using (var uow = IoC.Resolve<IUnitOfWork>()) { RoleInitialDataBuilder.Build(uow); } } [OneTimeTearDown] public void TearDown() { } [Test] [TestCase("Role1")] public void Should_Create_New_Role(string role) { var viewModel = new RoleCreateViewModel { Name = role }; _roleService.Create(viewModel); using (var context = IoC.Resolve<IUnitOfWork>()) { var user = context.Set<Role>().FirstOrDefault(a => a.Name == role); user.ShouldNotBeNull(); } } [Test] public void Should_Not_Create_New_Role_With_Admin_Name() { var viewModel = new RoleCreateViewModel { Name = "Admin" }; Assert.Throws<DbUpdateException>(() => _roleService.Create(viewModel)); } [Test] public void Should_AdminRole_Exists() { using (var context = IoC.Resolve<IUnitOfWork>()) { var user = context.Set<Role>().FirstOrDefault(a => a.Name == "Admin"); user.ShouldNotBeNull(); } } [Test] public void Should_Not_Create_New_Role_Without_Name() { Assert.Throws<ValidationException>(() => _roleService.Create(new RoleCreateViewModel { Name = null })); } } }
با این خروجی:
داشبورد Angular رایگان ng2-admin
ویژگیها :
- Angular 2+
- Angular CLI
- Bootstrap 4 CSSFramework
- SASS
- Smart Table
- Forms
- Editors
- Charts (amChart, Chartist, Chart.js,Morris)
- Maps (Google, Leaflet,amMap)
- Responsive layout
- High resolution
- and many more!
کتابخانه gridstack.js
gridstack.js is a jQuery plugin for widget layout. This is drag-and-drop multi-column grid. It allows you to build draggable responsive bootstrap v3 friendly layouts. It also works great with knockout.js, angular.js and touch devices. Demo Demo
Live Charts برای WPF
کتابخانه osm
It is an HTML5/Css3 responsive solution for using (and making) animated large off-screen menus. It uses CSS transitions that are hardware accellerated and much faster then jQuey animations.
It comes packed with presets (20 responsive presets and 30 presets for the editor), included Visual Editor and it is compatible with all modern desktop (HTML5) and mobile browsers (Android and iOS).
فقط mvc هست که امکان استفاده از چند view engine را با هم دارد.
صفحهای که لینک دادید مربوط است به asp.net web pages و نه web forms. این web pages برای کار با webmatrix طراحی شده.