???????????????????ó???
???????????? ???????[ 2016/8/3 16:57:56 ] ??????????????? ???????
?????????
????????????д?????????????????С??λ?????????????????????У??????????????????磬????????????????????File???????????????DummyFile?????????????????????????????????????????????????????????class???????????/???????л???????????????????á???????????????IFile??IDatabase????????????File??Database??
??????????????????????????????????????????????????鰴????????????????????????????????????м??????????磺???????CunsomerData??????????LINQ to SQL???????????????????У?????????????????????????????
??????????????TDD?????????????????????????????д????????????д??????????磬??д????????????CustomerData??????????????????CustomerData????CustomerData???????????????InsertCustomer ??DeleteCustomer ?? GetCustomer????????????????????Щ????Customer???????????????? ?????????????????????????????????д??CustomerData????????????????????????????????д????????????????????и????????TDD?????????????????????????????С????е??????????????????磬CustomerData????????SqlConnection?????????ISqlConnection ?????е?????????CustomerData????
??????????????????
?????????????????????????鷳????????д????????????????????????????????????????????????????У????????????????????????????????????????????????????
???磺?????????Stack ?????????????????Pop??????????????????е????????????????????????????????κζ??????Pop????????????????????????Pop?????????????????????????????????????Pop ??
???BDD???????
???????????У?????????е?????????????????LINQ??SQL???????????????????????????檔???磬??????????????????????????????棬????????????????棬?????У???????????м???????????????????????????PageRepository ?????????漰Page?????????????????????????o??????CRUD????????????????????GetPageById ????????PageId???????Page????????С?
public class PageRepository : IPageRepository
{
#region Fields
private readonly IDropthingsDataContext _database;
private readonly ICache _cacheResolver;
#endregion Fields
#region Constructors
public PageRepository(IDropthingsDataContext database?? ICache cacheResolver)
{
this._database = database;
this._cacheResolver = cacheResolver;
}
#endregion Constructors
#region Methods
public Page GetPageById(int pageId)
{
string cacheKey = CacheSetup.CacheKeys.PageId(pageId);
object cachedPage = _cacheResolver.Get(cacheKey);
if (null == cachedPage)
{
var page = _database.GetSingle<Page?? int>(
DropthingsDataContext.SubsystemEnum.Page??
pageId??
LinqQueries.CompiledQuery_GetPageById);
page.Detach();
_cacheResolver.Add(cacheKey?? page);
return page;
}
else
{
return cachedPage as Page;
}
}
}
PageRepository???IDropthingsDataContext ???????????LINQ to SQL???????λDataContext ?????????£?LINQ??SQL????????DataContext??????????????ò??????????DataContext?????????????????????ICache?????????漰???????????????У???????????????EnterpriseLibraryCache???????ICache ??
?????????????????????PageRepository??????????棬?? GetPageById??????PageId ?????????黺?棬?????????У???????????е?????м???????????????檔
public void GetPage_Should_Return_A_Page_from_database_when_cache_is_empty_and_then_caches_it()
{
var cache = new Mock<ICache>();
var database = new Mock<IDropthingsDataContext>();
IPageRepository pageRepository = new PageRepository(database.Object?? cache.Object);
const int pageId = 1;
var page = default(Page);
var samplePage = new Page() { ID = pageId?? Title = "Test Page"?? ...};
database
.Expect<Page>(d => d.GetSingle<Page?? int>(
DropthingsDataContext.SubsystemEnum.Page??
1?? LinqQueries.CompiledQuery_GetPageById))
.Returns(samplePage);
"Given PageRepository and empty cache".Context(() =>
{
// cache is empty
cache.Expect(c => c.Get(It.IsAny<string>())).Returns(default(object));
// It will cache the Page object afte loading from database
cache.Expect(c =>
c.Add(It.Is<string>(cacheKey =>
cacheKey == CacheSetup.CacheKeys.PageId(pageId))??
It.Is<Page>(cachePage =>
object.ReferenceEquals(cachePage?? samplePage))))
.AtMostOnce().Verifiable();
});
"when GetPageById is called".Do(() =>
page = pageRepository.GetPageById(1));
"it checks in the cache first and finds nothing and then caches it".Assert(() =>
cache.VerifyAll());
"it loads the page from database".Assert(() =>
database.VerifyAll());
"it returns the page as expected".Assert(() =>
{
Assert.Equal<int>(pageId?? page.ID);
});
}
????????????????
?????д?????????????????????????????ò????????????????????е?????????????????????????á?????????????У???????cache??database????????о?????????????????????????????磬??????????????AspectF?????????????PageRepository ??????????????????PageRepository??????????????????????????????????棬????????仺?????????黺?棬?????????????????????????????У???????????м?????????????????GetPageById??????AspectF ???????????
public Page GetPageById(int pageId)
{
return AspectF.Define
.Cache<Page>(_cacheResolver?? CacheSetup.CacheKeys.PageId(pageId))
.Return<Page>(() =>
_database.GetSingle<Page?? int>(DropthingsDataContext.SubsystemEnum.Page??
pageId?? LinqQueries.CompiledQuery_GetPageById).Detach());
}
????????????е?????????????????
????????PageRepository??и???????????????仯?????????????????????????????и????????????????????????????????????????????????????????????????????????????????з?????????????????????????????????????齫?????
[Specification]
public void GetPage_Should_Return_A_Page_from_cache_when_it_is_already_cached()
{
var cache = new Mock<ICache>();
var database = new Mock<IDropthingsDataContext>();
IPageRepository pageRepository = new PageRepository(database.Object?? cache.Object);
const int pageId = 1;
var page = default(Page);
var samplePage = new Page() { ID = pageId?? Title = "Test Page"??
ColumnCount = 3?? LayoutType = 3?? UserId = Guid.Empty?? VersionNo = 1??
PageType = Enumerations.PageTypeEnum.PersonalPage??
CreatedDate = DateTime.Now };
"Given PageRepository and the requested page in cache".Context(() =>
{
cache.Expect(c => c.Get(CacheSetup.CacheKeys.PageId(samplePage.ID)))
.Returns(samplePage);
});
"when GetPageById is called".Do(() =>
page = pageRepository.GetPageById(1));
"it checks in the cache first and finds the object is in cache".Assert(() =>
{
cache.VerifyAll();
});
"it returns the page as expected".Assert(() =>
{
Assert.Equal<int>(pageId?? page.ID);
});
}
????????????????????????????Context ???????趨?????????????????????????????????????samplePage???????????κα????ú???????????????????Mock???????????????????????????κ?database??????κζ??????????cache???????????????????????????????????????????????
??????????BDD
?????????ζ???????????Щ??????????????????????????????????????????????????????д????????????????????????????????κ????????????????????????????????????????б????????????????????????
??β?????????????????????????????????????????ó???????????????????????????????????????????磬??Dropthings ???????????μ?????????????????????????????С????????Щ????С?????????????塣????????anon_user@dropthings.com???????????????????С?????????????????????С?????????????????????С?????????????????????????????????????????
???????η????Default.aspx????FirstVisitHomePage?????Facade????????????????????????????楨С????????????????????????????????????FirstVisitHomePage?????ò??????????μ??????????????????????????????????????????????????????????? ??????????????????????????????????? ?????????η???? ??????????к?λ?????anon_user??????′???????洴????С??????
public class TestUserVisit
{
public TestUserVisit()
{
Facade.BootStrap();
}
/// <summary>
/// Ensure the first visit produces the pages and widgets defined in the template user
/// </summary>
[Specification]
public void First_visit_should_create_same_pages_and_widgets_as_the_template_user()
{
MembershipHelper.UsingNewAnonUser((profile) =>
{
using (var facade = new Facade(new AppContext(string.Empty?? profile.UserName)))
{
UserSetup userVisitModel = null;
// Load the anonymous user pages and widgets
string anonUserName = facade.GetUserSettingTemplate()
.AnonUserSettingTemplate.UserName;
var anonPages = facade.GetPagesOfUser(facade.GetUserGuidFromUserName(anonUserName));
"Given anonymous user who has never visited the site before"
.Context(() => { });
"when the user visits for the first time".Do(() =>
{
userVisitModel = facade.FirstVisitHomePage(profile.UserName??
string.Empty?? true?? false);
});
"it creates widgets on the newly created page at exact columns and
positions as the anon user's pages".Assert(() =>
{
anonPages.Each(anonPage =>
{
var userPage = userVisitModel.UserPages.First(page =>
page.Title == anonPage.Title
&& page.OrderNo == anonPage.OrderNo
&& page.PageType == anonPage.PageType);
facade.GetColumnsInPage(anonPage.ID).Each(anonColumn =>
{
var userColumns = facade.GetColumnsInPage(userPage.ID);
var userColumn = userColumns.First(column =>
column.ColumnNo == anonColumn.ColumnNo);
var anonColumnWidgets =
facade.GetWidgetInstancesInZoneWithWidget(anonColumn.WidgetZoneId);
var userColumnWidgets =
facade.GetWidgetInstancesInZoneWithWidget(userColumn.WidgetZoneId);
// Ensure the widgets from the anonymous user template's columns are
// in the same column and row.
anonColumnWidgets.Each(anonWidget =>
Assert.True(userColumnWidgets.Where(userWidget =>
userWidget.Title == anonWidget.Title
&& userWidget.Expanded == anonWidget.Expanded
&& userWidget.State == anonWidget.State
&& userWidget.Resized == anonWidget.Resized
&& userWidget.Height == anonWidget.Height
&& userWidget.OrderNo == anonWidget.OrderNo).Count() == 1));
});
});
});
}
});
}
???????????????????????????????????????????????????????????????????????檔?????????????????????С??????????????????????????仯???????????????????????????????λ?????????????????м??????????????????????????????????????????????????????κε???? ????xunit.console.exe?????е??????????????????????html???棺
??????????????????в?????
d:xunitxunit.console.exe
d: runksrcDropthings.Business.Facade.TestsinDebugDropthings.Business.Facade.Tests.dll
/html FacadeTest.html
?????????GUI xUnit:
???BDD???????????????????
???????????????????????д??????????????????д?????й???????????????????????????????????PageRepository ???? Insert??????????????????????в?????棬?????????????棬???????κλ??漯????????2??????檔
??????
???·???
??????????????????
2023/3/23 14:23:39???д?ò??????????
2023/3/22 16:17:39????????????????????Щ??
2022/6/14 16:14:27??????????????????????????
2021/10/18 15:37:44???????????????
2021/9/17 15:19:29???·???????·
2021/9/14 15:42:25?????????????
2021/5/28 17:25:47??????APP??????????
2021/5/8 17:01:11