Boolran Microsoft.TeamFoundation.VersionCpntrol.Client.Workspace.OwnerNameMatches(System.String)
خلاصه برای حل مشکل راهی جز آنیستال پچ که باز مشکل حل نشد و آخر مجبور شدم اول سرویس پک و بعد خود ویژوال استودیو رو اونطور که توصیه شده بود آنیستال و اینستال کنم. من بشخصه از SVN برای نگهداری کدها استفاده میکنم.
بازبینی اشاره گر ها:
در کنار هر گره علامتی نمایان میشود که وضعیت code amp در آن لحظه برای آن گره را نمایش میدهد.
تغییر نمای دیاگرام:
برای تغییر نمای گراف code map و نمایش بهتر آن از گزینه layout یکی از حالات موجود را میتوانید انتخاب نمایید. هر وقت گره ای اضافه شود که قبلا اضافه شده باشد رنگ آن سبر میشود برای پاک کردن این چنین گرههای گزینه clear Result Highlighting را انتخاب نمایید.
Test Driven Development #2
با تشکر. روش دوم بدون استفاده از ری شارپر:
در VS 2012 بعد از نصب NUnit Test adaptor ، میشه از Visual Studio 2012 Test Runner مستقیما برای کار با NUnit استفاده کرد.
خلاصه مهاجرت داده پروفایل ها
- کلاس جدیدی بسازید که دارای خواصی برای ذخیره اطلاعات پروفایل است.
- کلاس جدیدی بسازید که از 'ProfileBase' ارث بری میکند و متدهای لازم برای دریافت پروفایل کاربران را پیاده سازی میکند.
- استفاده از تامین کنندههای پیش فرض را، در فایل web.config فعال کنید. و کلاسی که در مرحله 2 ساختید را بعنوان کلاس پیش فرض برای خواندن اطلاعات پروفایل معرفی کنید.
شروع به کار
پوشه جدیدی با نام 'Models' بسازید تا اطلاعات پروفایل را در آن قرار دهیم.
بعنوان یک مثال، بگذارید تا تاریخ تولد کاربر، شهر سکونت، قد و وزن او را در پروفایلش ذخیره کنیم. قد و وزن بصورت یک کلاس سفارشی (custom class) بنام 'PersonalStats' ذخیره میشوند. برای ذخیره و بازیابی پروفایل ها، به کلاسی احتیاج داریم که 'ProfileBase' را ارث بری میکند. پس کلاس جدیدی با نام 'AppProfile' بسازید.
public class ProfileInfo { public ProfileInfo() { UserStats = new PersonalStats(); } public DateTime? DateOfBirth { get; set; } public PersonalStats UserStats { get; set; } public string City { get; set; } } public class PersonalStats { public int? Weight { get; set; } public int? Height { get; set; } } public class AppProfile : ProfileBase { public ProfileInfo ProfileInfo { get { return (ProfileInfo)GetPropertyValue("ProfileInfo"); } } public static AppProfile GetProfile() { return (AppProfile)HttpContext.Current.Profile; } public static AppProfile GetProfile(string userName) { return (AppProfile)Create(userName); } }
پروفایل را در فایل web.config خود فعال کنید. نام کلاسی را که در مرحله قبل ساختید، بعنوان کلاس پیش فرض برای ذخیره و بازیابی پروفایلها معرفی کنید.
<profile defaultProvider="DefaultProfileProvider" enabled="true" inherits="UniversalProviders_ProfileMigrations.Models.AppProfile"> <providers> ..... </providers> </profile>
برای دریافت اطلاعات پروفایل از کاربر، فرم وب جدیدی در پوشه Account بسازید و آنرا 'AddProfileData.aspx' نامگذاری کنید.
<h2> Add Profile Data for <%# User.Identity.Name %></h2> <asp:Label Text="" ID="Result" runat="server" /> <div> Date of Birth: <asp:TextBox runat="server" ID="DateOfBirth"/> </div> <div> Weight: <asp:TextBox runat="server" ID="Weight"/> </div> <div> Height: <asp:TextBox runat="server" ID="Height"/> </div> <div> City: <asp:TextBox runat="server" ID="City"/> </div> <div> <asp:Button Text="Add Profile" ID="Add" OnClick="Add_Click" runat="server" /> </div>
کد زیر را هم به فایل code-behind اضافه کنید.
protected void Add_Click(object sender, EventArgs e) { AppProfile profile = AppProfile.GetProfile(User.Identity.Name); profile.ProfileInfo.DateOfBirth = DateTime.Parse(DateOfBirth.Text); profile.ProfileInfo.UserStats.Weight = Int32.Parse(Weight.Text); profile.ProfileInfo.UserStats.Height = Int32.Parse(Height.Text); profile.ProfileInfo.City = City.Text; profile.Save(); }
دقت کنید که فضای نامی که کلاس AppProfile در آن قرار دارد را وارد کرده باشید.
اپلیکیشن را اجرا کنید و کاربر جدیدی با نام 'olduser' بسازید. به صفحه جدید 'AddProfileData' بروید و اطلاعات پروفایل کاربر را وارد کنید.
با استفاده از پنجره Server Explorer میتوانید تایید کنید که اطلاعات پروفایل با فرمت xml در جدول 'Profiles' ذخیره میشوند.
مهاجرت الگوی دیتابیس
اسکریپت مورد نیاز را از آدرس https://raw.github.com/suhasj/UniversalProviders-Identity-Migrations/master/Migration.txt دریافت کرده و آن را اجرا کنید. اگر اتصال خود به دیتابیس را تازه کنید خواهید دید که جداول جدیدی اضافه شده اند. میتوانید دادههای این جداول را بررسی کنید تا ببینید چگونه اطلاعات منتقل شده اند.
مهاجرت اپلیکیشن برای استفاده از ASP.NET Identity
- Microsoft.AspNet.Identity.EntityFramework
- Microsoft.AspNet.Identity.Owin
- Microsoft.Owin.Host.SystemWeb
- Microsoft.Owin.Security.Facebook
- Microsoft.Owin.Security.Google
- Microsoft.Owin.Security.MicrosoftAccount
- Microsoft.Owin.Security.Twitter
using Microsoft.AspNet.Identity.EntityFramework; using System; using System.Collections.Generic; using System.Linq; using System.Web; using UniversalProviders_ProfileMigrations.Models; namespace UniversalProviders_Identity_Migrations { public class User : IdentityUser { public User() { CreateDate = DateTime.UtcNow; IsApproved = false; LastLoginDate = DateTime.UtcNow; LastActivityDate = DateTime.UtcNow; LastPasswordChangedDate = DateTime.UtcNow; Profile = new ProfileInfo(); } public System.Guid ApplicationId { get; set; } public bool IsAnonymous { get; set; } public System.DateTime? LastActivityDate { get; set; } public string Email { get; set; } public string PasswordQuestion { get; set; } public string PasswordAnswer { get; set; } public bool IsApproved { get; set; } public bool IsLockedOut { get; set; } public System.DateTime? CreateDate { get; set; } public System.DateTime? LastLoginDate { get; set; } public System.DateTime? LastPasswordChangedDate { get; set; } public System.DateTime? LastLockoutDate { get; set; } public int FailedPasswordAttemptCount { get; set; } public System.DateTime? FailedPasswordAttemptWindowStart { get; set; } public int FailedPasswordAnswerAttemptCount { get; set; } public System.DateTime? FailedPasswordAnswerAttemptWindowStart { get; set; } public string Comment { get; set; } public ProfileInfo Profile { get; set; } } }
انتقال داده پروفایلها به جداول جدید
آخرین نسخه پکیج Entity Framework را نصب کنید. همچنین یک رفرنس به اپلیکیشن وب پروژه بدهید (کلیک راست روی پروژه و گزینه 'Add Reference').
کد زیر را در کلاس Program.cs وارد کنید. این قطعه کد پروفایل تک تک کاربران را میخواند و در قالب 'ProfileInfo' آنها را serialize میکند و در دیتابیس ذخیره میکند.
public class Program { var dbContext = new ApplicationDbContext(); foreach (var profile in dbContext.Profiles) { var stringId = profile.UserId.ToString(); var user = dbContext.Users.Where(x => x.Id == stringId).FirstOrDefault(); Console.WriteLine("Adding Profile for user:" + user.UserName); var serializer = new XmlSerializer(typeof(ProfileInfo)); var stringReader = new StringReader(profile.PropertyValueStrings); var profileData = serializer.Deserialize(stringReader) as ProfileInfo; if (profileData == null) { Console.WriteLine("Profile data deserialization error for user:" + user.UserName); } else { user.Profile = profileData; } } dbContext.SaveChanges(); }
برخی از مدلهای استفاده شده در پوشه 'IdentityModels' تعریف شده اند که در پروژه اپلیکیشن وبمان قرار دارند، بنابراین افزودن فضاهای نام مورد نیاز فراموش نشود.
کد بالا روی دیتابیسی که در پوشه App_Data وجود دارد کار میکند، این دیتابیس در مراحل قبلی در اپلیکیشن وب پروژه ایجاد شد. برای اینکه این دیتابیس را رفرنس کنیم باید رشته اتصال فایل app.config اپلیکیشن کنسول را بروز رسانی کنید. از همان رشته اتصال web.config در اپلیکیشن وب پروژه استفاده کنید. همچنین آدرس فیزیکی کامل را در خاصیت 'AttachDbFilename' وارد کنید.
یک Command Prompt باز کنید و به پوشه bin اپلیکیشن کنسول بالا بروید. فایل اجرایی را اجرا کنید و نتیجه را مانند تصویر زیر بررسی کنید.
در پنجره Server Explorer جدول 'AspNetUsers' را باز کنید. حال ستونهای این جدول باید خواص کلاس مدل را منعکس کنند.
کارایی سیستم را تایید کنید
به روز رسانی SQL Server Data Tools
-Tp $(TargetPath)
نکته : فقط در Vs.Net با نسخههای Ultimate و Premium میتونید از Code UI Test استفاده کنید که البته به دلیل اینکه در ایران پیدا کردن نسخههای دیگر Vs.Net به غیر از Ultimate سختتر است به طور قطع این محدودیت برای برنامه نویسان ما وجود نخواهد داشت. برای اینکه از نسخه Vs.Net خود اطمینان حاصل کنید از منوی Help گزینه About Microsoft Visual Studio رو انتخاب کنید. پنجره ای به شکل زیر مشاهده خواهید کرد که در آن مشخصات کامل Vs.Net ذکر شده است.
در این مرحله قصد داریم برای فرم زیر Unit Test طراحی کنیم. پروژه به صورت زیر است:
کاملا واضح است که در این فرم دو عدد به عنوان ورودی دریافت میشود و بعد از کلیک بر روی CalculateSum نتیجه در textbox سوم نمایش داده میشود. برای تست عملکرد صحیح فرم بالا ایتدا به Solution مورد نظر از منوی test Project یک Coded UI Test Project اضافه میکنیم. به دلیل اینکه این قبلا در این Solution پروژه تست از نوع Coded UI Test نبود بلافاصله یک پنجره نمایش داده میشود. مطمئن شوید گزینه اول انتخاب شده و بعد بر روی Ok کلیک کنید.(گزینه اول به معنی است که قصد داریم عملیات مورد نظر بر روی UI را رکورد کنیم و گزینه دوم به معنی است که قصد داریم از عملیات رکورد شده قبلی استفاده کنیم). یک کلاس به نام CodeUITest1 به همراه یک متد تست به نام CodedUITestMethod1 ساخته میشود. اولین چیزی که جلب توجه میکند این است که این کلاس به جای TestClassAttribute دارای نشان CodeUITestAttrbiute است. در گوشه سمت راست Vs.Net خود یک پنجره کوچک به نام UI Map Test Builder مانند شکل زیر خواهید دید.دکمه قرمز رنگ به نام Record Button است و عملیات تست را رکورد خواهد کرد. دکمه دایره ای به رنگ مشکی برای تعیین Assertion به کار میرود. و در نهایت گزینه آخر کدهای مورد نظر مراحل قبل را به صورت خودکار تولید خواهد کرد.
#روش کار
روش کار به این صورت است که ابتدا شما مراحل تست خود را شبیه سازی خواهید کرد و بعد از آن Test Builder مراحل تست شما را به صورت کامل به صورت کدهای قابل فهم تولید خواهد کرد. (دقیقا شبیه به ایجاد UnitTest به روش Arrange/Act/Assert است با این تفاوت که این مراحل توسط UI Map رکورد شده و نیازی به کد نویسی ندارد). در پایان باید یک Data Driven Coded UI Test طراحی کنید تا بتوانید از این مراحل رکورد استفاده نمایید.
#چگونگی شبیه سازی :
پروژه را اجرا نمایید. زمانی که فرم مورد نظر ظاهر شد بر روی گزینه Record در TestBuilder کلیک کنید. عملیات ذخیره سازی شروع شده است. در نتیجه به فرم مربوطه رفته و در Textbox اول مقدار 10 و در textbox دوم مقدار 5 را وارد نمایید. با کلیک بر روی دکمه CalculateSum مقدار 15 نمایش داده خواهد شد. از برنامه خارج شوید و بعد بر روی گزینه Generate Code در TestBuilder کلیک کنید با از کلیدهای ترکیبی Alt + G استفاده نمایید.(اگر در این مرحله، از برنامه خارج نشده باشید با خطا مواجه خواهید شد.) در پنجره نمایش داده شده یک نام به متد اختصاص دهید. عملیات تولید کد شروع خواهد شد. بعد کدی مشابه زیر را در متد مربوطه مشاهده خواهید کرد.
[TestMethod] public void CodedUITestMethod1() { this.UIMap.CalculateSum(); this.UIMap.txtSecondValueMustBe10(); }
public void CodedUITestMethod1 ()
{
#region Variable Declarations
WinEdit uITxtFirstNumberEdit = this.UIدوعددصحیحواردنماییدWindow.UITxtFirstNumberWindow.UITxtFirstNumberEdit;
WinEdit uITxtSecondNumberEdit = this.UIدوعددصحیحواردنماییدWindow.UITxtSecondNumberWindow.UITxtSecondNumberEdit;
WinButton uICalculateSumButton = this.UIدوعددصحیحواردنماییدWindow.UICalculateSumWindow.UICalculateSumButton;
#endregion
// Type '10' in 'txtFirstNumber' text box
uITxtFirstNumberEdit.Text = this.CalculateSumParams.UITxtFirstNumberEditText;
// Type '{Tab}' in 'txtFirstNumber' text box
Keyboard.SendKeys(uITxtFirstNumberEdit, this.CalculateSumParams.UITxtFirstNumberEditSendKeys, ModifierKeys.None);
// Type '10' in 'txtSecondNumber' text box
uITxtSecondNumberEdit.Text = this.CalculateSumParams.UITxtSecondNumberEditText;
// Click 'Calculate Sum' button
Mouse.Click(uICalculateSumButton, new Point(83, 12));
// Type '10' in 'txtFirstNumber' text box
uITxtFirstNumberEdit.Text = this.CalculateSumParams.UITxtFirstNumberEditText1;
// Type '{Tab}' in 'txtFirstNumber' text box
Keyboard.SendKeys(uITxtFirstNumberEdit, this.CalculateSumParams.UITxtFirstNumberEditSendKeys1, ModifierKeys.None);
// Type '10' in 'txtSecondNumber' text box
uITxtSecondNumberEdit.Text = this.CalculateSumParams.UITxtSecondNumberEditText1;
// Type '{Tab}' in 'txtSecondNumber' text box
Keyboard.SendKeys(uITxtSecondNumberEdit, this.CalculateSumParams.UITxtSecondNumberEditSendKeys, ModifierKeys.None);
// Click 'Calculate Sum' button
Mouse.Click(uICalculateSumButton, new Point(49, 11));
// Type '10' in 'txtFirstNumber' text box
uITxtFirstNumberEdit.Text = this.CalculateSumParams.UITxtFirstNumberEditText2;
// Type '{Tab}' in 'txtFirstNumber' text box
Keyboard.SendKeys(uITxtFirstNumberEdit, this.CalculateSumParams.UITxtFirstNumberEditSendKeys2, ModifierKeys.None);
// Type '5' in 'txtSecondNumber' text box
uITxtSecondNumberEdit.Text = this.CalculateSumParams.UITxtSecondNumberEditText2;
// Type '{Tab}' in 'txtSecondNumber' text box
Keyboard.SendKeys(uITxtSecondNumberEdit, this.CalculateSumParams.UITxtSecondNumberEditSendKeys1, ModifierKeys.None);
// Click 'Calculate Sum' button
Mouse.Click(uICalculateSumButton, new Point(74, 16));
}
چگونگی ایجاد Assertion
اگر به کد متد تست CodedUITestMethod1 در بالا دقت کنید یک متد به صورت this.UIMap.txtSecondValueMustBe10 فراخوانی شده است. این در واقع یک Assertion است که در هنگام عملیات رکورد ایجاد کردم و به این معنی است که مقدار TextBox دوم حتما باید 10 باشد. حال روش تولید Assertionها را بررسی خواهیم کرد.
بعد از شروع شدن مرحله رکورد اگر قصد دارید برای یک کنترل خاص Assert بنویسید، دکمه assertion (به رنگ مشکی و به صورت دایره است) را بر روی کنترل مورد نظر drag&drop کنید. یک border آبی برای کنترل مورد نظر ایجاد خواهد شد:
به محض اتمام عملیات drag&drop منوی زیر ظاهر خواهد شد:
از گزینه Add Assertion استفاده کنید و برای کنترل مورد نظر یک assert بنویسید. در شکل زیر یک assert برای textbox دوم نوشتم به صورتی که مقدار آن باید با 5 برابر باشد.از گزینه آخر برای نمایش پیغام مورد نظر خودتون در هنگامی که aseert با شکست مواجه میشود استفاده کنید.
کد تولید شده زیر برای عملیات assert بالا است:
public void txtSecondValueMustBe10() { #region Variable Declarations WinEdit uITxtSecondNumberEdit = this.UIدوعددصحیحواردنماییدWindow.UITxtSecondNumberWindow.UITxtSecondNumberEdit; #endregion // Verify that the 'ControlType' property of 'txtSecondNumber' text box equals '10' Assert.AreEqual(this.txtSecondValueMustBe10ExpectedValues.UITxtSecondNumberEditControlType, uITxtSecondNumberEdit.ControlType.ToString()); }
مرحله اول انجام شد. برای تست این مراحل باید یک Data DrivenTest بسازید که در پست بعدی به صورت کامل شرح داده خواهد شد.