
ASP.NET MVC Урок 1-F / ASP.NET MVC Урок E
.pdf
PRFN 6HWXS IRR ! IRR 'R6RPHWKLQJUHVHW7KURZV ,QYDOLG2SHUDWLRQ([FHSWLRQ!
PRFN 6HWXS IRR ! IRR 'R6RPHWKLQJ 7KURZVQHZ $UJXPHQW([FHSWLRQFRPPDQG
возвращает различные значения для (???) и использование Callback
YDUPRFN QHZ0RFN ,)RR!
YDUFDOOV
PRFN 6HWXS IRR ! IRR *HW&RXQW7KLQJ
5HWXUQV ! FDOOV
&DOOEDFN ! FDOOV
Соответсвие на аргументы любое значение
PRFN 6HWXS IRR ! IRR 'R6RPHWKLQJ ,W ,V$Q\VWULQJ! 5HWXUQVWUXH
условие через Func<bool, T>
PRFN 6HWXS IRR ! IRR$GG ,W ,VLQW! L ! L 5HWXUQVWUXH
нахождение в диапазоне
PRFN 6HWXS IRR ! IRR$GG ,W ,V,Q5DQJHLQW! 5DQJH ,QFOXVLYH 5HWXUQVWUXH
Regex выражение
PRFN 6HWXS [ ! [ 'R6RPHWKLQJ ,W ,V5HJH[>D G@5HJH[2SWLRQV ,JQRUH&DVH 5HWXUQ
VIRR
Свойства Любое свойство
PRFN 6HWXS IRR ! IRR 1DPH 5HWXUQVEDU
Любой иерархии свойство
PRFN 6HWXS IRR ! IRR %DU %D] 1DPH 5HWXUQVED]
Обратные вызовы (callback) Без параметров
PRFN 6HWXS IRR ! IRR ([HFXWHSLQJ
5HWXUQVWUXH

&DOOEDFN ! FDOOV
С параметром
PRFN 6HWXS IRR ! IRR ([HFXWH ,W ,V$Q\VWULQJ!
5HWXUQVWUXH
&DOOEDFNVWULQJV ! FDOOV$GG V
С параметром, немного другой синтаксис
PRFN 6HWXS IRR ! IRR ([HFXWH ,W ,V$Q\VWULQJ!
5HWXUQVWUXH
&DOOEDFNVWULQJ! V ! FDOOV$GG V
Несколько параметров
PRFN 6HWXS IRR ! IRR ([HFXWH ,W ,V$Q\LQW! ,W ,V$Q\VWULQJ!
5HWXUQVWUXH
&DOOEDFNLQW VWULQJ! L V ! FDOOV$GG V
До и после вызова
PRFN 6HWXS IRR ! IRR ([HFXWHSLQJ
&DOOEDFN ! &RQVROH :ULWH/LQH%HIRUH UHWXUQV
5HWXUQVWUXH
&DOOEDFN ! &RQVROH :ULWH/LQH $IWHU UHWXUQV
Проверка (Mock объект сохраняет количество обращений к своим параметрам, тем самым мы также можем проверить правильно ли был исполнен код)
Обычная проверка, что был вызван метод Execute с параметром “ping”
PRFN 9HULI\ IRR ! IRR ([HFXWHSLQJ
С добавлением собственного сообщения об ошибке
PRFN 9HULI\ IRR ! IRR ([HFXWHSLQJ :KHQ GRLQJ RSHUDWLRQ ; WKH VHUYLFH VKRX
OG EH SLQJHG DOZD\V
Не должен был быть вызван ни разу
PRFN 9HULI\ IRR ! IRR ([HFXWHSLQJ7LPHV 1HYHU

Хотя бы раз должен был быть вызван
PRFN 9HULI\ IRR ! IRR ([HFXWHSLQJ7LPHV$W/HDVW2QFH
PRFN 9HULI\*HW IRR ! IRR 1DPH
Должен был быть вызван именно сеттер для свойства
PRFN 9HULI\6HW IRR ! IRR 1DPH
Должен был быть вызван сеттер со значением “foo”
PRFN 9HULI\6HW IRR ! IRR 1DPH IRR
Сеттер должен был быть вызван со значением в заданном диапазоне
PRFN 9HULI\6HW IRR ! IRR 9DOXH ,W ,V,Q5DQJH 5DQJH ,QFOXVLYH
Хорошо, этого нам пока хватит, остальное можно будет почитать здесь: https://code.google.com/p/moq/wiki/QuickStart
Возвращаемся обратно в UnitTestSetupFixture.cs (/Setup/UnitTestSetupFixture.cs) и
инициализируем конфиг:
SURWHFWHG YLUWXDO YRLG ,QLW5HSRVLWRU\6WDQGDUG.HUQHO NHUQHO
^
NHUQHO %LQG 0RFN5HSRVLWRU\! 7R 0RFN5HSRVLWRU\! ,Q7KUHDG6FRSH
NHUQHO %LQG ,5HSRVLWRU\! 7R0HWKRG S ! NHUQHO *HW 0RFN5HSRVLWRU\! 2EMHFW
`
Проверим какойто наш вывод, например класс /Default/Controllers/UserController:cs:
>7HVW@
SXEOLF YRLG ,QGH[B*HW3DJHDEOH'DWD2I8VHUVB&RXQW2I8VHUV,V7ZR
^
LQLW
YDUFRQWUROOHU 'HSHQGHQF\5HVROYHU &XUUHQW *HW6HUYLFH$UHDV 'HIDXOW &RQWUROOHU V 8VHU&RQWUROOHU!
DFW
YDUUHVXOW FRQWUROOHU ,QGH[
$VVHUW ,V,QVWDQFH2I 9LHZ5HVXOW! UHVXOW
$VVHUW ,V,QVWDQFH2I 3DJHDEOH'DWD 8VHU!! 9LHZ5HVXOW UHVXOW 0RGHO
YDUFRXQW 3DJHDEOH'DWD 8VHU! 9LHZ5HVXOW UHVXOW 0RGHO /LVW &RXQW

$VVHUW$UH(TXDO FRXQW
`
В BaseController.cs (/LessonProject/Controllers/BaseController.cs) уберем атрибуты ,QMHFWу
свойств $XWK и &RQILJ (иначе выделенная строка не сможет проинициализовать контроллер и вернет null). Кстати о выделенной строке. Мы делаем именно такую инициализацию, чтобы все Injectатрибутованные свойства были проинициализированы. Запускаем, и, правда, count == 2. Отлично, MockRepository работает. Вернем назад атрибуты ,QMHFW. Кстати, тесты не запускаются обычно в дебагрежиме, чтобы запустить Debug надо сделать так:
Теперь поработаем с Config. Это будет круто!
TestConfig
Что нам нужно сделать. Нам нужно:
Взять Web.Config c проекта LessonProject (какимто хитрым образом)
И на его базе создать некий класс, который будет реализовывать IConfig интерфейс
Ну и поцепить на Ninject Kernel И можно использовать.
Начнем. Для того чтобы взять Web.Config – нам нужно скопировать его в свою папку.
Назовем её Sandbox. Теперь скопируем, поставим на prebuild Event в Project Properties:

[FRS\ 6ROXWLRQ'LU /HVVRQ3URMHFW?:HE FRQILJ 3URMHFW'LU 6DQGER[? \
При каждом запуске билда мы копируем Web.config (и, если надо, то перезаписываем) к
себе в Sandbox.
Создадим TestConfig.cs и в конструктор будем передавать наш файл (/Tools/TestConfig.cs):
SXEOLF FODVV 7HVW&RQILJ ,&RQILJ
^
SULYDWH&RQILJXUDWLRQ FRQILJXUDWLRQ
SXEOLF 7HVW&RQILJ VWULQJFRQILJ3DWK
^
YDUFRQILJ)LOH0DS QHZ([H&RQILJXUDWLRQ)LOH0DS
FRQILJ)LOH0DS ([H&RQILJ)LOHQDPH FRQILJ3DWK
FRQILJXUDWLRQ &RQILJXUDWLRQ0DQDJHU 2SHQ0DSSHG([H&RQILJXUDWLRQ FRQILJ)LOH0DS &RQILJXUDWLRQ8VHU/HYHO 1RQH
`
SXEOLF VWULQJ &RQQHFWLRQ6WULQJV VWULQJFRQQHFWLRQ6WULQJ
^

UHWXUQFRQILJXUDWLRQ &RQQHFWLRQ6WULQJV &RQQHFWLRQ6WULQJV>FRQQHFWLRQ6WULQJ@ &RQQ HFWLRQ6WULQJ
`
SXEOLF VWULQJ/DQJ
^
JHW
^
UHWXUQFRQILJXUDWLRQ$SS6HWWLQJV 6HWWLQJV>/DQJ@ 9DOXH
`
`
SXEOLF ERRO(QDEOH0DLO
^
JHW
^
UHWXUQ ERRO3DUVH FRQILJXUDWLRQ$SS6HWWLQJV 6HWWLQJV>(QDEOH0DLO@ 9DOXH
`
`
SXEOLF,4XHU\DEOH ,FRQ6L]H! ,FRQ6L]HV
^
JHW
^
,FRQ6L]HV&RQILJ6HFWLRQ FRQILJ,QIR ,FRQ6L]HV&RQILJ6HFWLRQ FRQILJXUDWLRQ * HW6HFWLRQLFRQ&RQILJ
LIFRQILJ,QIR QXOO
^
UHWXUQFRQILJ,QIR ,FRQ6L]HV 2I7\SH ,FRQ6L]H!$V4XHU\DEOH ,FRQ6L]H!
`
UHWXUQ QXOO
`
`
SXEOLF,4XHU\DEOH 0LPH7\SH! 0LPH7\SHV
^
JHW
^
0LPH7\SHV&RQILJ6HFWLRQ FRQILJ,QIR 0LPH7\SHV&RQILJ6HFWLRQ FRQILJXUDWLRQ * HW6HFWLRQPLPH&RQILJ
UHWXUQFRQILJ,QIR 0LPH7\SHV 2I7\SH 0LPH7\SH!$V4XHU\DEOH 0LPH7\SH!
`
`
SXEOLF,4XHU\DEOH 0DLO7HPSODWH! 0DLO7HPSODWHV
^
JHW^

0DLO7HPSODWH&RQILJ6HFWLRQ FRQILJ,QIR 0DLO7HPSODWH&RQILJ6HFWLRQ FRQILJXUD WLRQ *HW6HFWLRQPDLO7HPSODWHV&RQILJ
UHWXUQFRQILJ,QIR 0DLO7HPSODWHV 2I7\SH 0DLO7HPSODWH!$V4XHU\DEOH 0DLO7HPS ODWH!
`
`
SXEOLF0DLO6HWWLQJ 0DLO6HWWLQJ
^
JHW
^
UHWXUQ0DLO6HWWLQJ FRQILJXUDWLRQ *HW6HFWLRQPDLO&RQILJ
`
`
SXEOLF6PV6HWWLQJ 6PV6HWWLQJ
^
JHW
^
UHWXUQ6PV6HWWLQJ FRQILJXUDWLRQ *HW6HFWLRQVPV&RQILJ
`
`
`
И инициализируем в UnitTestSetupFixture.cs (/Setup/UnitTestSetupFixture.cs):
SURWHFWHG YLUWXDO YRLG ,QLW&RQILJ6WDQGDUG.HUQHO NHUQHO
^
YDUIXOO3DWK QHZ)LOH,QIR 6DQGER[:HE FRQILJ)XOO1DPH
NHUQHO %LQG ,&RQILJ! 7R0HWKRG F !QHZ7HVW&RQILJ IXOO3DWK
`
Создадим простой тест на проверку данных в конфиге:
>7HVW)L[WXUH@
SXEOLF FODVV 0DLO7HPSODWH7HVW
^
>7HVW@
SXEOLF YRLG 0DLO7HPSODWHVB([LVW5HJLVWHU7HPSODWHB([LVW
^
YDUFRQILJ 'HSHQGHQF\5HVROYHU &XUUHQW *HW6HUYLFH ,&RQILJ!
YDUWHPSODWH FRQILJ 0DLO7HPSODWHV )LUVW2U'HIDXOW S ! S 1DPH 6WDUWV:LWK5HJL VWHU
$VVHUW ,V1RW1XOO WHPSODWH
`

`
Запускаем, проверяем, вуаля! Переходим к реализации IAuthentication.
Authentication
В вебприложении, когда мы уже исполняем код в контроллере, мы уже имеем какойто заданный контекст, окружение, сформированное httpзапросом. Т.е. это и параметры, и кукисы, и данные о версии браузера, и каково разрешение экрана, и какая операционная система. В общем, это всё – HttpContext. Следует понимать, что мы при авторизации помещаем в кукисы какието данные, а потом достаем их и всё. Собственно, для этого мы создадим специальный интерфейс IAuthCookieProvider, который будет типа записывать кукисы
IAuthCookieProvider.cs (LessonProject/Global/Auth/IAuthCookieProvider):
SXEOLF LQWHUIDFH ,$XWK&RRNLH3URYLGHU
^
+WWS&RRNLH*HW&RRNLH VWULQJFRRNLH1DPH
YRLG 6HW&RRNLH+WWS&RRNLH FRRNLH
`
И реализуем его для HttpAuthCookieProvider.cs (/Global/Auth/HttpAuthCookieProvider.cs):
SXEOLF FODVV +WWS&RQWH[W&RRNLH3URYLGHU ,$XWK&RRNLH3URYLGHU
^
SXEOLF +WWS&RQWH[W&RRNLH3URYLGHU+WWS&RQWH[W +WWS&RQWH[W
^
WKLV+WWS&RQWH[W +WWS&RQWH[W
`
SURWHFWHG+WWS&RQWH[W +WWS&RQWH[W ^JHW VHW`
SXEOLF+WWS&RRNLH*HW&RRNLH VWULQJFRRNLH1DPH
^
UHWXUQ+WWS&RQWH[W 5HTXHVW &RRNLHV *HW FRRNLH1DPH
`
SXEOLF YRLG 6HW&RRNLH+WWS&RRNLH FRRNLH
^
+WWS&RQWH[W 5HVSRQVH &RRNLHV 6HW FRRNLH
`
`

И теперь используем эту реализацию для работы с Cookies в CustomAuthentication (/Global/Auth/CustomAuthentication.cs):
SXEOLF,$XWK&RRNLH3URYLGHU$XWK&RRNLH3URYLGHU ^JHW VHW`
и вместо HttpContext.Request.Cookies.Get – используем GetCookie() и HttpContext.Response.Cookies.Set – соответственно SetCookie(). Изменяем и в IAuthencation.cs (/Global/Auth/IAuthencation.cs):
SXEOLF LQWHUIDFH ,$XWKHQWLFDWLRQ
^
VXPPDU\!
Ʉɨɧɟɤɫɬ ɬɭɬ ɦɵ ɩɨɥɭɱɚɟɦ ɞɨɫɬɭɩ ɤ ɡɚɩɪɨɫɭ ɢ ɤɭɤɢɫɚɦ
VXPPDU\!
,$XWK&RRNLH3URYLGHU$XWK&RRNLH3URYLGHU ^JHW VHW`
И в AuthHttpModule.cs (/Global/Auth/AuthHttpModule.cs):
YDUDXWK 'HSHQGHQF\5HVROYHU &XUUHQW *HW6HUYLFH ,$XWKHQWLFDWLRQ!
DXWK$XWK&RRNLH3URYLGHU QHZ+WWS&RQWH[W&RRNLH3URYLGHU FRQWH[W
MockHttpContext
Теперь создадим Mockобъекты для HttpContext в LessonProject.UnitTest:
0RFN+WWS&RQWH[W FV ɜ 0RFN +WWS&RQWH[W FV SXEOLF FODVV 0RFN+WWS&RQWH[W 0RFN +WWS&RQWH[W%DVH!
^
>,QMHFW@
SXEOLF+WWS&RRNLH&ROOHFWLRQ &RRNLHV ^JHW VHW`
SXEOLF0RFN+WWS&DFKH3ROLF\ &DFKH ^JHW VHW`
SXEOLF0RFN+WWS%URZVHU&DSDELOLWLHV %URZVHU ^JHW VHW`
SXEOLF0RFN+WWS6HVVLRQ6WDWH 6HVVLRQ6WDWH ^JHW VHW`
SXEOLF0RFN+WWS6HUYHU8WLOLW\ 6HUYHU8WLOLW\ ^JHW VHW`
SXEOLF0RFN+WWS5HVSRQVH 5HVSRQVH ^JHW VHW`
SXEOLF0RFN+WWS5HTXHVW 5HTXHVW ^JHW VHW`

SXEOLF 0RFN+WWS&RQWH[W0RFN%HKDYLRU PRFN%HKDYLRU 0RFN%HKDYLRU 6WULFW
WKLV QXOOPRFN%HKDYLRU
^
`
SXEOLF 0RFN+WWS&RQWH[W,$XWKHQWLFDWLRQ DXWK 0RFN%HKDYLRU PRFN%HKDYLRU 0RFN%HKDYL RU 6WULFW
EDVHPRFN%HKDYLRU
^
UHTXHVW
%URZVHU QHZ0RFN+WWS%URZVHU&DSDELOLWLHV PRFN%HKDYLRU
%URZVHU 6HWXS E ! E ,V0RELOH'HYLFH 5HWXUQVIDOVH
5HTXHVW QHZ0RFN+WWS5HTXHVW PRFN%HKDYLRU
5HTXHVW 6HWXS U ! U &RRNLHV 5HWXUQV &RRNLHV
5HTXHVW 6HWXS U ! U 9DOLGDWH,QSXW
5HTXHVW 6HWXS U ! U 8VHU$JHQW 5HWXUQV0R]LOOD :LQGRZV 17 :2:$S SOH:HE.LW .+70/ OLNH *HFNR &KURPH 6DIDUL
5HTXHVW 6HWXS U ! U %URZVHU 5HWXUQV %URZVHU 2EMHFW
WKLV6HWXS S ! S 5HTXHVW 5HWXUQV 5HTXHVW 2EMHFW
UHVSRQVH
&DFKH QHZ0RFN+WWS&DFKH3ROLF\ 0RFN%HKDYLRU /RRVH
5HVSRQVH QHZ0RFN+WWS5HVSRQVH PRFN%HKDYLRU
5HVSRQVH 6HWXS U ! U &RRNLHV 5HWXUQV &RRNLHV
5HVSRQVH 6HWXS U ! U &DFKH 5HWXUQV &DFKH 2EMHFW
WKLV6HWXS S ! S 5HVSRQVH 5HWXUQV 5HVSRQVH 2EMHFW
XVHU
LIDXWK QXOO
^
WKLV6HWXS S ! S 8VHU 5HWXUQV ! DXWK &XUUHQW8VHU
`
HOVH
^
WKLV6HWXS S ! S 8VHU 5HWXUQVQHZ8VHU3URYLGHU QXOO
`
6HVVLRQ 6WDWH
6HVVLRQ6WDWH QHZ0RFN+WWS6HVVLRQ6WDWH
WKLV6HWXS S ! S 6HVVLRQ 5HWXUQV 6HVVLRQ6WDWH 2EMHFW
6HUYHU 8WLOLW\
6HUYHU8WLOLW\ QHZ0RFN+WWS6HUYHU8WLOLW\ PRFN%HKDYLRU
WKLV6HWXS S ! S 6HUYHU 5HWXUQV 6HUYHU8WLOLW\ 2EMHFW