рдХреЙрд▓рдмреИрдХ (рдХреЙрд▓рдмреИрдХ)
- рдХреЛрдИ рдкреИрд░рд╛рдореАрдЯрд░ рдирд╣реАрдВ
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"));
рдЪреЗрдХ рдХрд░реЗрдВ (рдореЙрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рдЕрдкрдиреЗ рдорд╛рдкрджрдВрдбреЛрдВ рдкрд░ рдХреЙрд▓ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдмрдЪрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рд╣рдо рдпрд╣ рднреА рдЬрд╛рдВрдЪ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рдХреЛрдб рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛)
- рд╕рд╛рдорд╛рдиреНрдп рдЬрд╛рдВрдЪ рдпрд╣ рд╣реИ рдХрд┐ рдПрдХреНрдЬрд╝реЗрдХреНрдпреВрдЯ рд╡рд┐рдзрд┐ рдХреЛ "рдкрд┐рдВрдЧ" рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд╕рд╛рде рдХрд╣рд╛ рдЬрд╛рддрд╛ рдерд╛
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);
- рдореВрд▓реНрдп "рдлреВ" рдХреЗ рд╕рд╛рде рдПрдХ рд╕реЗрдЯрд░ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдерд╛
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); }
рдЖрдЗрдП, рд╣рдорд╛рд░реЗ рдХреБрдЫ рдЖрдЙрдЯрдкреБрдЯ рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдХреНрд▓рд╛рд╕ / рдбрд┐рдлреЙрд▓реНрдЯ / рдХрдВрдЯреНрд░реЛрд▓рд░ / рдпреВрдЬрд░ рдХрдВрдЯреНрд░реЛрд▓рд░: рд╕реАрдПрд╕:
[Test] public void Index_GetPageableDataOfUsers_CountOfUsersIsTwo() {
BaseController.cs (/LessonProject/Controllers/BaseController.cs) рдореЗрдВ, рд╣рдо рдкреНрд░рд╛рдорд╛рдгрд┐рдХ рдФрд░ Config
рдЧреБрдгреЛрдВ рд╕реЗ Inject
рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рд╣рдЯрд╛ рджреЗрддреЗ рд╣реИрдВ (рдЕрдиреНрдпрдерд╛ рдЪрдпрдирд┐рдд рд▓рд╛рдЗрди рдирд┐рдпрдВрддреНрд░рдХ рдХреЛ рдкреНрд░рд╛рд░рдВрдн рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдирд╣реАрдВ рд╣реЛрдЧреА рдФрд░ рд╡рд┐рдХрд▓реНрдк рд╢реВрдиреНрдп рд╣реЛ рдЬрд╛рдПрдВрдЧреЗ)ред рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХреА рдЧрдИ рд▓рд╛рдЗрди рдХреА рдмрд╛рдд рдХрд░рдирд╛ред рд╣рдо рдЗрд╕ рдЖрд░рдВрднреАрдХрд░рдг рдХреЛ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рд╕рднреА рдЗрдВрдЬреЗрдХреНрдЯ-рд╡рд┐рд╢реЗрд╖рддрд╛ рдЧреБрдг рдЖрд░рдВрднреАрдХреГрдд рд╣реЛрддреЗ рд╣реИрдВред рд╣рдо рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░, рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЧрд┐рдирддреА == 2. рдорд╣рд╛рди, рдореЙрдХрд░реЗрдкреЛрд╕рд┐рдЯрд░реА рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред Inject
рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рд╡рд╛рдкрд╕ рд▓рд╛рдПрдВред
рд╡реИрд╕реЗ, рдЖрдорддреМрд░ рдкрд░ рдкрд░реАрдХреНрд╖рдг рдбрд┐рдмрдЧ рдореЛрдб рдореЗрдВ рдирд╣реАрдВ рдЪрд▓рддреЗ рд╣реИрдВ, рдбреАрдмрдЧ рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдпрд╣ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

рдЕрдм рд╡рд┐рдиреНрдпрд╛рд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рдХрдорд╛рд▓ рд╣реЛрдЧрд╛!
TestConfig
рд╣рдореЗрдВ рдХреНрдпрд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдП:
- LessonProject рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд╕реЗ Web.Config рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ (рдХреБрдЫ рдореБрд╢реНрдХрд┐рд▓ рддрд░реАрдХреЗ рд╕реЗ)
- рдФрд░ рдЗрд╕рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╡рд░реНрдЧ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЛ IConfig рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдЧрд╛
- рдЦреИрд░, Ninject рдХрд░реНрдиреЗрд▓ рдкрд░ рд╣реБрдХ
- рдФрд░ рдЖрдк рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдЪрд▓рд┐рдП рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред Web.Config рд▓реЗрдиреЗ рдХреЗ рд▓рд┐рдП - рд╣рдореЗрдВ рдЗрд╕реЗ рдЕрдкрдиреЗ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдХреЙрдкреА рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдЪрд▓реЛ рдЗрд╕реЗ рд╕реИрдВрдбрдмреЙрдХреНрд╕ рдХрд╣рддреЗ рд╣реИрдВред рдЕрдм рдХреЙрдкреА рдХрд░реЗрдВ, рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрд┐рд▓реНрдб рдореЗрдВ рдкреНрд░реА-рдмрд┐рд▓реНрдб рдЗрд╡реЗрдВрдЯ рдкрд░ рд░рдЦреЗрдВ:

xcopy $(SolutionDir)LessonProject\Web.config $(ProjectDir)Sandbox\ /y
рд╣рд░ рдмрд╛рд░ рдЬрдм рдЖрдк рдирд┐рд░реНрдорд╛рдг рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рд╕реИрдВрдбрдмреЙрдХреНрд╕ рдореЗрдВ рдЦреБрдж рдХреЛ 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 рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред
рдкреНрд░рдорд╛рдгреАрдХрд░рдг
рдПрдХ рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ, рдЬрдм рд╣рдо рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрдВрдЯреНрд░реЛрд▓рд░ рдореЗрдВ рдХреЛрдб рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХреБрдЫ рджрд┐рдП рдЧрдП рд╕рдВрджрд░реНрдн рд╣реИрдВ, рдЬреЛ рдХрд┐ http рдЕрдиреБрд░реЛрдз рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рдпрд╛рдиреА рдпреЗ рдкреИрд░рд╛рдореАрдЯрд░, рдХреБрдХреАрдЬрд╝ рдФрд░ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕рдВрд╕реНрдХрд░рдг рдбреЗрдЯрд╛ рд╣реИрдВ, рдФрд░ рд╕реНрдХреНрд░реАрди рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди рдХреНрдпрд╛ рд╣реИ, рдФрд░ рдХреМрди рд╕рд╛ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рд╣реИред рд╕рдм рд╕рдм рдореЗрдВ, рдпрд╣ HttpContext рд╣реИред рдпрд╣ рд╕рдордЭрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреЗ рджреМрд░рд╛рди рд╣рдо рдХреБрдХреАрдЬрд╝ рдореЗрдВ рдХреБрдЫ рдбреЗрдЯрд╛ рдбрд╛рд▓рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рд╣рдо рдпрд╣ рд╕рдм рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред рджрд░рдЕрд╕рд▓, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдо рдПрдХ рд╡рд┐рд╢реЗрд╖ 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) рдореЗрдВ рдХреБрдХреАрдЬрд╝ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ:
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; }); }
рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдмрд┐рдВрдб рд╕рд┐рдВрдЧрд▓рдЯрдирд╕реНрдХреЛрдк (), рдпрд╛рдиреА рдкрд░ рд╣реЛрддрд╛ рд╣реИред рдПрдХ рдмрд╛рд░ рдХреБрдЫ рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рд▓реЙрдЧ рдЗрди рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдо рдмрд╛рдж рдХреЗ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рдЙрд╕реА рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред
рд╕рдВрдХрд▓рд┐рдд рдХрд░реЗрдВ рдФрд░ рдЗрд╕ рд╕рдм рдХреЗ рд╕рд╛рде рдЙрддрд╛рд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред рдЬрд╛рджреВ рд╢реБрд░реВ рд╣реЛрдиреЗ рд╡рд╛рд▓рд╛ рд╣реИ ...
рд╕рддреНрдпрд╛рдкрди рдЬрд╛рдБрдЪ
рдЕрдЧрд░ рд╣рдо рдХреБрдЫ рдХрд╣рддреЗ рд╣реИрдВ:
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);
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдХреЛрдИ рдирд┐рд╣рд┐рдд рд╕рддреНрдпрд╛рдкрди рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рджреВрд╕рд░реА рдмрд╛рдд, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╡рд╣рд╛рдВ рд╕рддреНрд░ рд╣реИ рдФрд░ рд╣рдордиреЗ рдЗрд╕реЗ рдкреНрд░рд╛рд░рдВрдн рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ, рдпрд╣ рдЕрд╢рдХреНрдд рд╣реИ рдФрд░ рдпрд╣ рдПрдХ рддреНрд░реБрдЯрд┐ рд╣реИред рддреЛ рд╕рддреНрдпрд╛рдкрди рдЬрд╛рдВрдЪ (рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдореЗрдВ рдПрдХ) рдХреЛ рдПрдХ рдЕрд▓рдЧ рд╡рд░реНрдЧ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдЖрдЗрдП рдЗрд╕реЗ рд╡реИрд▓рд┐рдбреЗрдЯрд░ рд╡реИрд▓рд┐рдбреЗрдЯреЛрд░реЛрд╡рд┐рдЪ (/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); } } } } }
рддреЛ рдпрд╣рд╛рдВ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рд╣рдореЗрдВ рдХреНрд▓рд╛рд╕ T рдХреЗ рд╕рднреА рдЧреБрдг рдорд┐рд▓рддреЗ рд╣реИрдВ, рдЬреЛ рдХрд┐ ValidationAttribute рдкреНрд░рдХрд╛рд░ рдХреЗ рд╣реИрдВ:
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() {
рд╣рдо рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рд╕рдм рдХреБрдЫ рдирд┐рдХрд▓рд╛ред рд▓реЗрдХрд┐рди рдХреИрдкреНрдЪрд╛ рдХреЛ рдХрдВрдЯреНрд░реЛрд▓рд░ рдореЗрдердб рдореЗрдВ рд╕реАрдзреЗ рдЪреЗрдХ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдХреИрдкреНрдЪрд╛ рдХреЗ рд▓рд┐рдП:
[Test] public void Index_RegisterUserWithWrongCaptcha_ModelStateWithError() {
рдХреВрд▓!
рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреА рдЬрд╛рдБрдЪ
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдпрд╣ рджреЗрдЦрдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ рдпрджрд┐ рдореИрдВ рдкреНрд░рд╢рд╛рд╕рдХ рдХреЗ рдЕрдзреАрди рдирд╣реАрдВ рдЬрд╛рддрд╛ рд╣реВрдВ, рддреЛ рдЕрдзрд┐рдХреГрдд рднрд╛рдЧ рдореЗрдВ ([рдЕрдзрд┐рдХреГрдд (рднреВрдорд┐рдХрд╛ = рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ)] рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЗ рд╕рд╛рде рдЪрд┐рд╣реНрдирд┐рдд рдирд┐рдпрдВрддреНрд░рдХ рдореЗрдВ) рд╡рд┐рд╢реЗрд╖рддрд╛ - рд╕рд╛рдзрд╛рд░рдг рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рд╣реЛрдЧреАред рдЗрд╕реЗ рдЬрд╛рдВрдЪрдиреЗ рдХрд╛ рдПрдХ рд╢рд╛рдирджрд╛рд░ рддрд░реАрдХрд╛ рд╣реИред рдЪрд▓рд┐рдП рдХрдВрдЯреНрд░реЛрд▓рд░рдПрд╡реЗрд╢рдирдЗрдВрд╡рд░ рдХреНрд▓рд╛рд╕ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВ рдФрд░ рдЗрд╕реЗ рдХреЙрд▓ рдХреЗ рд▓рд┐рдП рдЗрдирд╣реЗрд░рд┐рдЯ рдХрд░реЗрдВ (/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); } }
рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, рдпрд╣ рдирд┐рдпрдВрддреНрд░рдХ рдПрдХреНрд╢рди рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ "рдЗрдирд╡реЙрдХрд░" рд╣реИ, рдЬрд╣рд╛рдВ рдЬреЗрдиреЗрд░рд┐рдХ рд╡рд░реНрдЧ рдЕрдкреЗрдХреНрд╖рд┐рдд рдкрд░рд┐рдгрд╛рдо рд╡рд░реНрдЧ рд╣реИред рдЕрдирдзрд┐рдХреГрддрддрд╛ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдпрд╣ 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"); } }
рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдПрдВ, рдпрд╣ рдЧреБрдЬрд░рддрд╛ рд╣реИред рдЖрдЗрдП, рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдЕрдзреАрди рдХрд░реЗрдВ рдФрд░ 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-,
рдкрд░реАрдХреНрд╖рдг рдПрдХ рдмрд╣реБрдд рдмрдбрд╝рд╛ рдХреНрд╖реЗрддреНрд░ рд╣реИ, рдпрд╣ рдПрдХ рдЕрд▓рдЧ рдкреЗрд╢рд╛ рдФрд░ рдорд╛рдирд╕рд┐рдХрддрд╛ рднреА рд╣реИ (рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкреНрд░реЛрдЧреНрд░рд╛рдореЗрдЯрд┐рдХ рдирд╣реАрдВ)ред рдФрд░ рдХреЛрдб рдХреА рдЧреБрдгрд╡рддреНрддрд╛ рди рдХреЗрд╡рд▓ рдкреНрд░реМрджреНрдпреЛрдЧрд┐рдХрд┐рдпреЛрдВ рдХреЗ рдЖрд╡реЗрджрди рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░реЗрдЧреА, рд╣рд╛рд▓рд╛рдВрдХрд┐, рдирд┐рд╕реНрд╕рдВрджреЗрд╣, рдЯреАрдбреАрдбреА рдХреЗ рддрд╛рд░реНрдХрд┐рдХ рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдХрд╛ рдкрд╛рд▓рди рдФрд░ рдХрд╛рд░реНрдпрдХреНрд░рдореЛрдВ рдХреЗ рд╡рд┐рдХрд╛рд╕ рдореЗрдВ рдЖрдВрддрд░рд┐рдХ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдПрдВ рдЖрдкрдХреЛ рдХрдИ рддреНрд░реБрдЯрд┐рдпреЛрдВ рд╕реЗ рдмрдЪрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИрдВред рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрдирд╛ рд╕рднреА рдмреАрдорд╛рд░рд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд░рд╛рдордмрд╛рдг рдирд╣реАрдВ рд╣реИ, рдпрд╣ рдПрдХ рдЙрдкрдХрд░рдг рд╣реИ, рдФрд░ рдЗрд╕реЗ рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ ...
рд╣рдордиреЗ рдЧреНрд░рд╛рд╣рдХ рднрд╛рдЧ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреА рдЙрдкреЗрдХреНрд╖рд╛ рдХреА, рдФрд░ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ, рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдХреЗрд╡рд▓ рдЕрдХреНрдЯреВрдмрд░ 2011 рдореЗрдВ, jQuery рдиреЗ qUnit рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛, рд▓реЗрдХрд┐рди рдЗрд╕ рдкрд░ рд▓рдЧрднрдЧ рдХреЛрдИ рдЬрд╛рдирдХрд╛рд░реА рдирд╣реАрдВ рд╣реИред
рд╕рднреА рд╕реНрд░реЛрдд https://bitbucket.org/chernikov/lessons рдкрд░ рд╕реНрдерд┐рдд рд╣реИрдВ