ã³ãŒã«ããã¯
- ãã©ã¡ãŒã¿ãªã
mock.Setup(foo => foo.Execute("ping")) .Returns(true) .Callback(() => calls++);
- ãã©ã¡ãŒã¿ä»ã
mock.Setup(foo => foo.Execute(It.IsAny<string>())) .Returns(true) .Callback((string s) => calls.Add(s));
- ãã©ã¡ãŒã¿ãŒã䜿çšãããšããããã«ç°ãªãæ§æ
mock.Setup(foo => foo.Execute(It.IsAny<string>())) .Returns(true) .Callback<string>(s => calls.Add(s));
ããã€ãã®ãã©ã¡ãŒã¿ãŒ
mock.Setup(foo => foo.Execute(It.IsAny<int>(), It.IsAny<string>())) .Returns(true) .Callback<int, string>((i, s) => calls.Add(s));
åŒã³åºãã®ååŸ
mock.Setup(foo => foo.Execute("ping")) .Callback(() => Console.WriteLine("Before returns")) .Returns(true) .Callback(() => Console.WriteLine("After returns"));
ãã§ãã¯ïŒã¢ãã¯ãªããžã§ã¯ãã¯ãã©ã¡ãŒã¿ãŒã®åŒã³åºãåæ°ãä¿åãããããã³ãŒããæ£ããå®è¡ããããã©ããã確èªã§ããŸãïŒ
- éåžžã®ãã§ãã¯ã¯ãExecuteã¡ãœããããpingããã©ã¡ãŒã¿ãŒã§åŒã³åºãããããšã§ãã
mock.Verify(foo => foo.Execute("ping"));
- ç¬èªã®ãšã©ãŒã¡ãã»ãŒãžã远å
mock.Verify(foo => foo.Execute("ping"), "When doing operation X, the service should be pinged always");
- äžåºŠåŒã³åºãããã¹ãã§ã¯ãªãã£ã
mock.Verify(foo => foo.Execute("ping"), Times.Never());
- å°ãªããšãäžåºŠã¯åŒã³åºããªããã°ãªããŸããã§ãã
mock.Verify(foo => foo.Execute("ping"), Times.AtLeastOnce()); mock.VerifyGet(foo => foo.Name);
- ããããã£ã®ã»ãã¿ãŒãåŒã³åºãããŠããå¿
èŠããããŸã
mock.VerifySet(foo => foo.Name);
- å€ãfooãã®ã»ãã¿ãŒãåŒã³åºãããŠããå¿
èŠããããŸã
mock.VerifySet(foo => foo.Name = "foo");
- ã»ãã¿ãŒã¯ãæå®ãããç¯å²ã®å€ã§åŒã³åºãããŠããå¿
èŠããããŸãã
mock.VerifySet(foo => foo.Value = It.IsInRange(1, 5, Range.Inclusive));
ããŠãããã§ããã§ååã§ããæ®ãã¯ããã§èªãããšãã§ããŸãïŒ
https://code.google.com/p/moq/wiki/QuickStart
UnitTestSetupFixture.csïŒ/Setup/UnitTestSetupFixture.csïŒã«æ»ããæ§æãåæåããŸãã
protected virtual void InitRepository(StandardKernel kernel) { kernel.Bind<MockRepository>().To<MockRepository>().InThreadScope(); kernel.Bind<IRepository>().ToMethod(p => kernel.Get<MockRepository>().Object); }
ã¯ã©ã¹ãããã©ã«ããã³ã³ãããŒã©ãŒãUserControllerãªã©ã®åºåã®äžéšã確èªããŸãããïŒcsïŒ
[Test] public void Index_GetPageableDataOfUsers_CountOfUsersIsTwo() {
BaseController.csïŒ/LessonProject/Controllers/BaseController.csïŒã§ã Auth
ããã³Config
ããããã£ããInject屿§ãåé€ããŸãïŒããããªããšãéžæããè¡ã¯ã³ã³ãããŒã©ãŒãåæåã§ãããnullãè¿ããŸãïŒã ãã€ã©ã€ããããè¡ãšããã°ã ãã¹ãŠã®Inject-attributeããããã£ãåæåãããããã«ããã®åæåãè¡ããŸãã éå§ããŸãããcount == 2ã§ããçŽ æŽããããMockRepositoryã¯åäœããŸãã Inject
屿§ãå
ã«æ»ããŸãã
ã¡ãªã¿ã«ããã¹ãã¯éåžžââãããã°ã¢ãŒãã§ã¯å®è¡ãããŸããããããã°ãå®è¡ããã«ã¯ããããè¡ãå¿
èŠããããŸãã

ããã§ã¯ãConfigãæäœããŸãããã ããã¯çŽ æŽãããã§ãããïŒ
Testconfig
äœãããå¿
èŠããããŸããã å¿
èŠãªãã®ïŒ
- LessonProjectãããžã§ã¯ãããWeb.ConfigãååŸããïŒããªãããŒãªæ¹æ³ã§ïŒ
- ãããŠãããã«åºã¥ããŠãIConfigã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ããç¹å®ã®ã¯ã©ã¹ãäœæããŸã
- ããŠãNinject Kernelã«ããã¯ãã
- ãããŠãããªãã¯ããã䜿ãããšãã§ããŸãã
å§ããŸãããã Web.ConfigãååŸããã«ã¯ããã©ã«ããŒã«ã³ããŒããå¿
èŠããããŸãã ãµã³ãããã¯ã¹ãšåŒã³ãŸãããã ã³ããŒããŠããããžã§ã¯ãããããã£ã®ãã«ãåã€ãã³ãã«é
眮ããŸãã

xcopy $(SolutionDir)LessonProject\Web.config $(ProjectDir)Sandbox\ /y
ãã«ããéå§ãããã³ã«ãSandboxã§Web.configãã³ããŒããŸãïŒå¿
èŠã«å¿ããŠäžæžãããŸãïŒã
TestConfig.csãäœæããŠããã¡ã€ã«ïŒ/Tools/TestConfig.csïŒãã³ã³ã¹ãã©ã¯ã¿ãŒã«è»¢éããŸãã
public class TestConfig : IConfig { private Configuration configuration; public TestConfig(string configPath) { var configFileMap = new ExeConfigurationFileMap(); configFileMap.ExeConfigFilename = configPath; configuration = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None); } public string ConnectionStrings(string connectionString) { return configuration.ConnectionStrings.ConnectionStrings[connectionString].ConnectionString; } public string Lang { get { return configuration.AppSettings.Settings["Lang"].Value; } } public bool EnableMail { get { return bool.Parse(configuration.AppSettings.Settings["EnableMail"].Value); } } public IQueryable<IconSize> IconSizes { get { IconSizesConfigSection configInfo = (IconSizesConfigSection)configuration.GetSection("iconConfig"); if (configInfo != null) { return configInfo.IconSizes.OfType<IconSize>().AsQueryable<IconSize>(); } return null; } } public IQueryable<MimeType> MimeTypes { get { MimeTypesConfigSection configInfo = (MimeTypesConfigSection)configuration.GetSection("mimeConfig"); return configInfo.MimeTypes.OfType<MimeType>().AsQueryable<MimeType>(); } } public IQueryable<MailTemplate> MailTemplates { get { MailTemplateConfigSection configInfo = (MailTemplateConfigSection)configuration.GetSection("mailTemplatesConfig"); return configInfo.MailTemplates.OfType<MailTemplate>().AsQueryable<MailTemplate>(); } } public MailSetting MailSetting { get { return (MailSetting)configuration.GetSection("mailConfig"); } } public SmsSetting SmsSetting { get { return (SmsSetting)configuration.GetSection("smsConfig"); } } }
UnitTestSetupFixture.csïŒ/Setup/UnitTestSetupFixture.csïŒã§åæåããŸãã
protected virtual void InitConfig(StandardKernel kernel) { var fullPath = new FileInfo(Sandbox + "/Web.config").FullName; kernel.Bind<IConfig>().ToMethod(c => new TestConfig(fullPath)); }
èšå®å
ã®ããŒã¿ããã§ãã¯ããç°¡åãªãã¹ããäœæããŸãããïŒ
[TestFixture] public class MailTemplateTest { [Test] public void MailTemplates_ExistRegisterTemplate_Exist() { var config = DependencyResolver.Current.GetService<IConfig>(); var template = config.MailTemplates.FirstOrDefault(p => p.Name.StartsWith("Register")); Assert.IsNotNull(template); } }
éå§ã確èªãåºæ¥äžããïŒ IAuthenticationã®å®è£
ã«æž¡ããŸãã
èªèšŒ
Webã¢ããªã±ãŒã·ã§ã³ã§ã¯ãã³ã³ãããŒã©ãŒã§ã³ãŒããæ¢ã«å®è¡ããŠãããšããç¹å®ã®ã³ã³ããã¹ãïŒhttpãªã¯ãšã¹ãã«ãã£ãŠåœ¢æãããç°å¢ïŒãæ¢ã«ãããŸãã ã€ãŸã ãããã¯ããã©ã¡ãŒã¿ãCookieããã©ãŠã¶ã®ããŒãžã§ã³ããŒã¿ãç»é¢è§£å床ãããã³ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã§ãã å
šäœãšããŠãããã¯HttpContextã§ãã æ¿èªäžã«äžéšã®ããŒã¿ãCookieã«å
¥ããŠãããã¹ãŠååŸããããšãçè§£ããŠããå¿
èŠããããŸãã å®éã«ã¯ããã®ããã«ãCookieãå
¥åããç¹å¥ãªIAuthCookieProviderã€ã³ã¿ãŒãã§ã€ã¹ãäœæããŸã
IAuthCookieProvider.csïŒLessonProject / Global / Auth / IAuthCookieProviderïŒïŒ
public interface IAuthCookieProvider { HttpCookie GetCookie(string cookieName); void SetCookie(HttpCookie cookie); }
ãããŠãHttpAuthCookieProvider.csïŒ/Global/Auth/HttpAuthCookieProvider.csïŒã«å®è£
ããŸãã
public class HttpContextCookieProvider : IAuthCookieProvider { public HttpContextCookieProvider(HttpContext HttpContext) { this.HttpContext = HttpContext; } protected HttpContext HttpContext { get; set; } public HttpCookie GetCookie(string cookieName) { return HttpContext.Request.Cookies.Get(cookieName); } public void SetCookie(HttpCookie cookie) { HttpContext.Response.Cookies.Set(cookie); } }
ãããŠããã®å®è£
ã䜿çšããŠãCustomAuthenticationïŒ/Global/Auth/CustomAuthentication.csïŒã®CookieãæäœããŸãã
public IAuthCookieProvider AuthCookieProvider { get; set; }
HttpContext.Request.Cookies.Getã®ä»£ããã«GetCookieïŒïŒã䜿çšãã
HttpContext.Response.Cookies.Set-ããããSetCookieïŒïŒã
IAuthencation.csïŒ/Global/Auth/IAuthencation.csïŒã§ã倿ŽããŸãã
public interface IAuthentication {
ãããŠAuthHttpModule.csïŒ/Global/Auth/AuthHttpModule.csïŒã§ïŒ
var auth = DependencyResolver.Current.GetService<IAuthentication>(); auth.AuthCookieProvider = new HttpContextCookieProvider(context);
MockHttpContext
LessonProject.UnitTestã§HttpContextã®ã¢ãã¯ãªããžã§ã¯ããäœæããŸãã
MockHttpContext.cs (/Mock/HttpContext.cs): public class MockHttpContext : Mock<HttpContextBase> { [Inject] public HttpCookieCollection Cookies { get; set; } public MockHttpCachePolicy Cache { get; set; } public MockHttpBrowserCapabilities Browser { get; set; } public MockHttpSessionState SessionState { get; set; } public MockHttpServerUtility ServerUtility { get; set; } public MockHttpResponse Response { get; set; } public MockHttpRequest Request { get; set; } public MockHttpContext(MockBehavior mockBehavior = MockBehavior.Strict) : this(null, mockBehavior) { } public MockHttpContext(IAuthentication auth, MockBehavior mockBehavior = MockBehavior.Strict) : base(mockBehavior) {
ããã«å ããŠã次ã®ãããªã¯ã©ã¹ãäœæããŸãã
- MockHttpCachePolicy
- MockHttpBrowserCapabilities
- MockHttpSessionState
- MockHttpServerUtility
- MockHttpResponse
- MockHttpRequest
ã»ãã·ã§ã³ã¹ãã¬ãŒãžãä¿åãããMockSessionStateïŒ/Mock/Http/MockHttpSessionState.csïŒãé€ããããããã¹ãŠã®ã¢ãã¯ãªããžã§ã¯ãã¯éåžžã«ç°¡åã§ãã
public class MockHttpSessionState : Mock<HttpSessionStateBase> { Dictionary<string, object> sessionStorage; public MockHttpSessionState(MockBehavior mockBehavior = MockBehavior.Strict) : base(mockBehavior) { sessionStorage = new Dictionary<string, object>(); this.Setup(p => p[It.IsAny<string>()]).Returns((string index) => sessionStorage[index]); this.Setup(p => p.Add(It.IsAny<string>(), It.IsAny<object>())).Callback<string, object>((name, obj) => { if (!sessionStorage.ContainsKey(name)) { sessionStorage.Add(name, obj); } else { sessionStorage[name] = obj; } }); } }
FakeAuthCookieProvider.csïŒ/Fake/FakeAuthCookieProvider.csïŒãäœæããŸãã
public class FakeAuthCookieProvider : IAuthCookieProvider { [Inject] public HttpCookieCollection Cookies { get; set; } public HttpCookie GetCookie(string cookieName) { return Cookies.Get(cookieName); } public void SetCookie(HttpCookie cookie) { if (Cookies.Get(cookie.Name) != null) { Cookies.Remove(cookie.Name); } Cookies.Add(cookie); } }
ãµãïŒ UnitTestSetupFixture.csïŒ/Setup/UnitTestSetupFixture.csïŒã§ãããåæåããŸãã
protected virtual void InitAuth(StandardKernel kernel) { kernel.Bind<HttpCookieCollection>().To<HttpCookieCollection>(); kernel.Bind<IAuthCookieProvider>().To<FakeAuthCookieProvider>().InSingletonScope(); kernel.Bind<IAuthentication>().ToMethod<CustomAuthentication>(c => { var auth = new CustomAuthentication(); auth.AuthCookieProvider = kernel.Get<IAuthCookieProvider>(); return auth; }); }
Bindã¯SingletonScopeïŒïŒã§çºçããããšã«æ³šæããŠãã ããã ãããã¹ãã«ãã°ã€ã³ãããšãåŸç¶ã®ãã¹ãã§åãèªèšŒã䜿çšããŸãã
ã³ã³ãã€ã«ããŠãããããã¹ãŠãå®è¡ããŠã¿ãŠãã ããã éæ³ãå§ãŸãããšããŠãã...
æ€èšŒãã§ãã¯
次ã®ãããªãã®ãåŒã³åºãå ŽåïŒ
var registerUser = new UserView() { Email = "user@sample.com", Password = "123456", ConfirmPassword = "1234567", AvatarPath = "/file/no-image.jpg", BirthdateDay = 1, BirthdateMonth = 12, BirthdateYear = 1987, Captcha = "1234" }; var result = controller.Register(registerUser);
第äžã«ãæé»ã®æ€èšŒã¯å®è¡ãããŸããã第äºã«ãããã§ã»ãã·ã§ã³ãããããããåæåããŸããã§ãããnullã§ãããããããã¹ãŠã§ã-ãšã©ãŒ ãã®ãããæ€èšŒãã§ãã¯ïŒå±æ§å
ã®ãã§ãã¯ïŒã¯å¥ã®ã¯ã©ã¹ãä»ããŠé
眮ãããŸãã Validator ValidatorovichïŒ/Tools/Validator.csïŒãšåŒã³ãŸãããïŒ
public class ValidatorException : Exception { public ValidationAttribute Attribute { get; private set; } public ValidatorException(ValidationException ex, ValidationAttribute attribute) : base(attribute.GetType().Name, ex) { Attribute = attribute; } } public class Validator { public static void ValidateObject<T>(T obj) { var type = typeof(T); var meta = type.GetCustomAttributes(false).OfType<MetadataTypeAttribute>().FirstOrDefault(); if (meta != null) { type = meta.MetadataClassType; } var typeAttributes = type.GetCustomAttributes(typeof(ValidationAttribute), true).OfType<ValidationAttribute>(); var validationContext = new ValidationContext(obj); foreach (var attribute in typeAttributes) { try { attribute.Validate(obj, validationContext); } catch (ValidationException ex) { throw new ValidatorException(ex, attribute); } } var propertyInfo = type.GetProperties(); foreach (var info in propertyInfo) { var attributes = info.GetCustomAttributes(typeof(ValidationAttribute), true).OfType<ValidationAttribute>(); foreach (var attribute in attributes) { var objPropInfo = obj.GetType().GetProperty(info.Name); try { attribute.Validate(objPropInfo.GetValue(obj, null), validationContext); } catch (ValidationException ex) { throw new ValidatorException(ex, attribute); } } } } }
ããã§äœãèµ·ãã£ãŠããã®ãã æåã«ãValidationAttributeåã®ã¯ã©ã¹Tã®ãã¹ãŠã®å±æ§ãååŸããŸãã
var typeAttributes = type.GetCustomAttributes(typeof(ValidationAttribute), true).OfType<ValidationAttribute>(); var validationContext = new ValidationContext(obj); foreach (var attribute in typeAttributes) { try { attribute.Validate(obj, validationContext); } catch (ValidationException ex) { throw new ValidatorException(ex, attribute); } }
次ã«ãåããããã£ã«ã€ããŠåæ§ã§ãïŒ
var propertyInfo = type.GetProperties(); foreach (var info in propertyInfo) { var attributes = info.GetCustomAttributes(typeof(ValidationAttribute), true).OfType<ValidationAttribute>(); foreach (var attribute in attributes) { var objPropInfo = obj.GetType().GetProperty(info.Name); try { attribute.Validate(objPropInfo.GetValue(obj, null), validationContext); } catch (ValidationException ex) { throw new ValidatorException(ex, attribute); } } }
æ€èšŒã倱æãããšãäŸå€ãçºçããValidatorExceptionã§ã©ããããŠãäŸå€ãçºçãã屿§ãæž¡ããŸãã
次ã«ããã£ããã£ãšã»ãã·ã§ã³ã«ã€ããŠèª¬æããŸãã ã³ã³ããã¹ããã³ã³ãããŒã©ãŒã«æž¡ãå¿
èŠããããŸãïŒMockHttpContextïŒïŒ
var controller = DependencyResolver.Current.GetService<Areas.Default.Controllers.UserController>(); var httpContext = new MockHttpContext().Object; ControllerContext context = new ControllerContext(new RequestContext(httpContext, new RouteData()), controller); controller.ControllerContext = context; controller.Session.Add(CaptchaImage.CaptchaValueKey, "1111");
ãããŠä»ããã¹ãŠäžç·ã«ïŒ
[Test] public void Index_RegisterUserWithDifferentPassword_ExceptionCompare() {
éå§ãããšããã¹ãŠã倿ããŸããã ãã ããcaptchaã¯ã³ã³ãããŒã©ãŒã¡ãœããã§çŽæ¥ãã§ãã¯ãããŸãã ç¹ã«ãã£ããã£ã®å ŽåïŒ
[Test] public void Index_RegisterUserWithWrongCaptcha_ModelStateWithError() {
ãã£ãããïŒ
èªå¯ãã§ãã¯
ããšãã°ã管çè
ã®äžã«ããªãå Žåã¯ãæ¿èªãããéšåïŒ[AuthorizeïŒRoles =â admin "ïŒ]屿§ã§ããŒã¯ãããã³ã³ãããŒã©ãŒïŒã§-éåžžã®ãŠãŒã¶ãŒãå
¥åã§ããªãããšã確èªããå¿
èŠããããŸãã ããã確èªããçŽ æŽãããæ¹æ³ããããŸãã ControllerActionInvokerã¯ã©ã¹ã«æ³šç®ããŠãåŒã³åºãã®ããã«ãããç¶æ¿ããŸãããïŒ/Fake/FakeControllerActionInvoker.cs + FakeValueProvider.csïŒïŒ
public class FakeValueProvider { protected Dictionary<string, object> Values { get; set; } public FakeValueProvider() { Values = new Dictionary<string, object>(); } public object this[string index] { get { if (Values.ContainsKey(index)) { return Values[index]; } return null; } set { if (Values.ContainsKey(index)) { Values[index] = value; } else { Values.Add(index, value); } } } } public class FakeControllerActionInvoker<TExpectedResult> : ControllerActionInvoker where TExpectedResult : ActionResult { protected FakeValueProvider FakeValueProvider { get; set; } public FakeControllerActionInvoker() { FakeValueProvider = new FakeValueProvider(); } public FakeControllerActionInvoker(FakeValueProvider fakeValueProvider) { FakeValueProvider = fakeValueProvider; } protected override ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) { return base.InvokeActionMethodWithFilters(controllerContext, filters, actionDescriptor, parameters); } protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) { var obj = FakeValueProvider[parameterDescriptor.ParameterName]; if (obj != null) { return obj; } return parameterDescriptor.DefaultValue; } protected override void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) { Assert.IsInstanceOf<TExpectedResult>(actionResult); } }
æ¬è³ªçã«ãããã¯ã³ã³ãããŒã©ã¢ã¯ã·ã§ã³ã¡ãœããã®ãåŒã³åºãåŽãã§ãããGenericã¯ã©ã¹ã¯äºæ³ãããçµæã¯ã©ã¹ã§ãã æ¿èªãããŠããªãå Žåã¯ãHttpUnauthorizedResultã«ãªããŸãã ãã¹ããè¡ããŸãããïŒ/Test/Admin/HomeControllerTest.csïŒïŒ
[TestFixture] public class AdminHomeControllerTest { [Test] public void Index_NotAuthorizeGetDefaultView_RedirectToLoginPage() { var auth = DependencyResolver.Current.GetService<IAuthentication>(); auth.Login("chernikov@gmail.com", "password2", false); var httpContext = new MockHttpContext(auth).Object; var controller = DependencyResolver.Current.GetService<Areas.Admin.Controllers.HomeController>(); var route = new RouteData(); route.Values.Add("controller", "Home"); route.Values.Add("action", "Index"); route.Values.Add("area", "Admin"); ControllerContext context = new ControllerContext(new RequestContext(httpContext, route), controller); controller.ControllerContext = context; var controllerActionInvoker = new FakeControllerActionInvoker<HttpUnauthorizedResult>(); var result = controllerActionInvoker.InvokeAction(controller.ControllerContext, "Index"); } }
ãã¹ããå®è¡ãããšãåæ ŒããŸãã , admin ViewResult:
[Test] public void Index_AdminAuthorize_GetViewResult() { var auth = DependencyResolver.Current.GetService<IAuthentication>(); auth.Login("admin", "password", false); var httpContext = new MockHttpContext(auth).Object; var controller = DependencyResolver.Current.GetService<Areas.Admin.Controllers.HomeController>(); var route = new RouteData(); route.Values.Add("controller", "Home"); route.Values.Add("action", "Index"); route.Values.Add("area", "Admin"); ControllerContext context = new ControllerContext(new RequestContext(httpContext, route), controller); controller.ControllerContext = context; var controllerActionInvoker = new FakeControllerActionInvoker<ViewResult>(); var result = controllerActionInvoker.InvokeAction(controller.ControllerContext, "Index"); }
. .
, . , , . . ? , , , . , Mock- , , , , ? , - ? NerdDinner .
IRepository, SqlRepository, MockRepository. SqlRepository â . . ã©ãããïŒ TDD?
, SqlRepository. Web.config ( ), , , , .
LessonProject.IntegrationTest Test.
Ninject, Moq NUnit:
Install-Package Ninject Install-Package Moq Install-Package NUnit
Sandbox Setup UnitTestSetupFixture (/Setup/IntegrationTestSetupFixture.cs) :
[SetUpFixture] public class IntegrationTestSetupFixture : UnitTestSetupFixture { public class FileListRestore { public string LogicalName { get; set; } public string Type { get; set; } } protected static string NameDb = "LessonProject"; protected static string TestDbName; private void CopyDb(StandardKernel kernel, out FileInfo sandboxFile, out string connectionString) { var config = kernel.Get<IConfig>(); var db = new DataContext(config.ConnectionStrings("ConnectionString")); TestDbName = string.Format("{0}_{1}", NameDb, DateTime.Now.ToString("yyyyMMdd_HHmmss")); Console.WriteLine("Create DB = " + TestDbName); sandboxFile = new FileInfo(string.Format("{0}\\{1}.bak", Sandbox, TestDbName)); var sandboxDir = new DirectoryInfo(Sandbox);
é çªã«ïŒ
var config = kernel.Get<IConfig>(); var db = new DataContext(config.ConnectionStrings("ConnectionString"));
â .
TestDbName = string.Format("{0}_{1}", NameDb, DateTime.Now.ToString("yyyyMMdd_HHmmss"));
.
â Sandbox.
var restoreFileList = string.Format("RESTORE FILELISTONLY FROM DISK = '{0}'", sandboxFile.FullName); var fileListRestores = db.ExecuteQuery<FileListRestore>(restoreFileList).ToList(); var logicalDbName = fileListRestores.FirstOrDefault(p => p.Type == "D"); var logicalLogDbName = fileListRestores.FirstOrDefault(p => p.Type == "L");
â , FIleListRestore.
var restoreDb = string.Format("RESTORE DATABASE [{0}] FROM DISK = '{1}' WITH FILE = 1, MOVE N'{2}' TO N'{4}\\{0}.mdf', MOVE N'{3}' TO N'{4}\\{0}.ldf', NOUNLOAD, STATS = 10", TestDbName, sandboxFile.FullName, logicalDbName.LogicalName, logicalLogDbName.LogicalName, sandboxDir.FullName); db.ExecuteCommand(restoreDb);
â (TestDbName)
connectionString = config.ConnectionStrings("ConnectionString").Replace(NameDb, TestDbName);
â connectionString.
IRepository SqlRepository:
protected override void InitRepository(StandardKernel kernel) { FileInfo sandboxFile; string connectionString; CopyDb(kernel, out sandboxFile, out connectionString); kernel.Bind<webTemplateDbDataContext>().ToMethod(c => new webTemplateDbDataContext(connectionString)); kernel.Bind<IRepository>().To<SqlRepository>().InTransientScope(); sandboxFile.Delete(); }
, sandboxFile â , connectionString â ( ). , SqlRepository, . . .
, :
private void RemoveDb() { var config = DependencyResolver.Current.GetService<IConfig>(); var db = new DataContext(config.ConnectionStrings("ConnectionString")); var textCloseConnectionTestDb = string.Format(@"ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", TestDbName); db.ExecuteCommand(textCloseConnectionTestDb); var textDropTestDb = string.Format(@"DROP DATABASE [{0}]", TestDbName); db.ExecuteCommand(textDropTestDb); }
TestDbName, ( ), .
Web.config:
xcopy $(SolutionDir)LessonProject\Web.config $(ProjectDir)Sandbox\ /y
, . , , . . â :
[TestFixture] public class DefaultUserControllerTest { [Test] public void CreateUser_CreateNormalUser_CountPlusOne() { var repository = DependencyResolver.Current.GetService<IRepository>(); var controller = DependencyResolver.Current.GetService<LessonProject.Areas.Default.Controllers.UserController>(); var countBefore = repository.Users.Count(); var httpContext = new MockHttpContext().Object; var route = new RouteData(); route.Values.Add("controller", "User"); route.Values.Add("action", "Register"); route.Values.Add("area", "Default"); ControllerContext context = new ControllerContext(new RequestContext(httpContext, route), controller); controller.ControllerContext = context; controller.Session.Add(CaptchaImage.CaptchaValueKey, "1111"); var registerUserView = new UserView() { ID = 0, Email = "rollinx@gmail.com", Password = "123456", ConfirmPassword = "123456", Captcha = "1111", BirthdateDay = 13, BirthdateMonth = 9, BirthdateYear = 1970 }; Validator.ValidateObject<UserView>(registerUserView); controller.Register(registerUserView); var countAfter = repository.Users.Count(); Assert.AreEqual(countBefore + 1, countAfter); } }
, email.
å®è¡ããŠç¢ºèªããŠãã ããã . ! , . - â , â . , , , MailNotify . :
/LessonProject/Tools/Mail/IMailSender.cs:
public interface IMailSender { void SendMail(string email, string subject, string body, MailAddress mailAddress = null); }
/LessonProject/Tools/Mail/MailSender.cs:
public class MailSender : IMailSender { [Inject] public IConfig Config { get; set; } private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); public void SendMail(string email, string subject, string body, MailAddress mailAddress = null) { try { if (Config.EnableMail) { if (mailAddress == null) { mailAddress = new MailAddress(Config.MailSetting.SmtpReply, Config.MailSetting.SmtpUser); } MailMessage message = new MailMessage( mailAddress, new MailAddress(email)) { Subject = subject, BodyEncoding = Encoding.UTF8, Body = body, IsBodyHtml = true, SubjectEncoding = Encoding.UTF8 }; SmtpClient client = new SmtpClient { Host = Config.MailSetting.SmtpServer, Port = Config.MailSetting.SmtpPort, UseDefaultCredentials = false, EnableSsl = Config.MailSetting.EnableSsl, Credentials = new NetworkCredential(Config.MailSetting.SmtpUserName, Config.MailSetting.SmtpPassword), DeliveryMethod = SmtpDeliveryMethod.Network }; client.Send(message); } else { logger.Debug("Email : {0} {1} \t Subject: {2} {3} Body: {4}", email, Environment.NewLine, subject, Environment.NewLine, body); } } catch (Exception ex) { logger.Error("Mail send exception", ex.Message); } } }
/LessonProject/Tools/Mail/NotifyMail.cs:
public static class NotifyMail { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private static IConfig _config; public static IConfig Config { get { if (_config == null) { _config = (DependencyResolver.Current).GetService<IConfig>(); } return _config; } } private static IMailSender _mailSender; public static IMailSender MailSender { get { if (_mailSender == null) { _mailSender = (DependencyResolver.Current).GetService<IMailSender>(); } return _mailSender; } } public static void SendNotify(string templateName, string email, Func<string, string> subject, Func<string, string> body) { var template = Config.MailTemplates.FirstOrDefault(p => string.Compare(p.Name, templateName, true) == 0); if (template == null) { logger.Error("Can't find template (" + templateName + ")"); } else { MailSender.SendMail(email, subject.Invoke(template.Subject), body.Invoke(template.Template)); } } }
/LessonProject/App_Start/NinjectWebCommon.cs:
private static void RegisterServices(IKernel kernel) {⊠kernel.Bind<IMailSender>().To<MailSender>(); }
LessonProject.UnitTest MockMailSender (/Mock/Mail/MockMailSender.cs):
public class MockMailSender : Mock<IMailSender> { public MockMailSender(MockBehavior mockBehavior = MockBehavior.Strict) : base(mockBehavior) { this.Setup(p => p.SendMail(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MailAddress>())) .Callback((string email, string subject, string body, MailAddress address) => Console.WriteLine(String.Format("Send mock email to: {0}, subject {1}", email, subject))); } }
UnitTestSetupFixture.cs (/LessonProject.UnitTest/Setup/UnitTestSetupFixture.cs):
protected virtual IKernel InitKernel() { ⊠kernel.Bind<MockMailSender>().To<MockMailSender>(); kernel.Bind<IMailSender>().ToMethod(p => kernel.Get<MockMailSender>().Object); return kernel; }
, , .
=============== =====START===== =============== Create DB = LessonProject_20130314_104218 Send mock email to: chernikov@googlemail.com, subject =============== =====BYE!====== ===============
, . () GenerateData Test, , . . â , . , ( , , ).
« », , , .
100 :
[Test] public void CreateUser_Create100Users_NoAssert() { var repository = DependencyResolver.Current.GetService<IRepository>(); var controller = DependencyResolver.Current.GetService<LessonProject.Areas.Default.Controllers.UserController>(); var httpContext = new MockHttpContext().Object; var route = new RouteData(); route.Values.Add("controller", "User"); route.Values.Add("action", "Register"); route.Values.Add("area", "Default"); ControllerContext context = new ControllerContext(new RequestContext(httpContext, route), controller); controller.ControllerContext = context; controller.Session.Add(CaptchaImage.CaptchaValueKey, "1111"); var rand = new Random((int)DateTime.Now.Ticks); for (int i = 0; i < 100; i++) { var registerUserView = new UserView() { ID = 0, Email = Email.GetRandom(Name.GetRandom(), Surname.GetRandom()), Password = "123456", ConfirmPassword = "123456", Captcha = "1111", BirthdateDay = rand.Next(28) + 1, BirthdateMonth = rand.Next(12) + 1, BirthdateYear = 1970 + rand.Next(20) }; controller.Register(registerUserView); } }
IntegrationTestSetupFixture.cs (/Setup/IntegrationTestSetupFixture.cs):
protected static bool removeDbAfter = false;
Web.config :
<add name="ConnectionString" connectionString="Data Source=SATURN-PC;Initial Catalog=LessonProject_20130314_111020;Integrated Security=True;Pooling=False" providerName="System.Data.SqlClient" />
:

ãŸãšã
:
- TDD
- NUnit
- Mock
- Unit-
- Integration-,
â , ( ). , , , TDD . â , , âŠ
, , , . JQuery 2011 qUnit, .
ãã¹ãŠã®ãœãŒã¹ã¯https://bitbucket.org/chernikov/lessonsã«ãããŸã