Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ASP.NET MVC Урок 1-F / ASP.NET MVC Урок E

.pdf
Скачиваний:
40
Добавлен:
09.03.2016
Размер:
830.69 Кб
Скачать

,WHPV

YDULWHPV QHZ/LVW'LFWLRQDU\

WKLV6HWXS S ! S ,WHPV 5HWXUQV LWHPV

`

`

Кроме этого создаем еще такие классы:

MockHttpCachePolicy

MockHttpBrowserCapabilities

MockHttpSessionState

MockHttpServerUtility

MockHttpResponse

MockHttpRequest

Все эти mock­объекты весьма тривиальны, кроме MockSessionState, где и хранится session­ storage (/Mock/Http/MockHttpSessionState.cs):

SXEOLF FODVV 0RFN+WWS6HVVLRQ6WDWH 0RFN +WWS6HVVLRQ6WDWH%DVH!

^

'LFWLRQDU\VWULQJ REMHFW! VHVVLRQ6WRUDJH

SXEOLF 0RFN+WWS6HVVLRQ6WDWH0RFN%HKDYLRU PRFN%HKDYLRU 0RFN%HKDYLRU 6WULFW

EDVHPRFN%HKDYLRU

^

VHVVLRQ6WRUDJH QHZ'LFWLRQDU\VWULQJ REMHFW!

WKLV6HWXS S ! S>,W ,V$Q\VWULQJ! @ 5HWXUQVVWULQJLQGH[ ! VHVVLRQ6WRUDJ H>LQGH[@

WKLV6HWXS S ! S$GG ,W ,V$Q\VWULQJ! ,W ,V$Q\REMHFW! &DOOEDFNVWULQJ REMHFW! QDPH REM !

^

LIVHVVLRQ6WRUDJH &RQWDLQV.H\ QDPH

^

VHVVLRQ6WRUDJH$GG QDPH REM

`

HOVH

^

VHVVLRQ6WRUDJH>QDPH@ REM

`

`

`

`

Создаем FakeAuthCookieProvider.cs (/Fake/FakeAuthCookieProvider.cs):

SXEOLF FODVV )DNH$XWK&RRNLH3URYLGHU ,$XWK&RRNLH3URYLGHU

^

>,QMHFW@

SXEOLF+WWS&RRNLH&ROOHFWLRQ &RRNLHV ^JHW VHW`

SXEOLF+WWS&RRNLH*HW&RRNLH VWULQJFRRNLH1DPH

^

UHWXUQ&RRNLHV *HW FRRNLH1DPH

`

SXEOLF YRLG 6HW&RRNLH+WWS&RRNLH FRRNLH

^

LI&RRNLHV *HW FRRNLH 1DPH QXOO

^

&RRNLHV 5HPRYH FRRNLH 1DPH

`

&RRNLHV$GG FRRNLH

`

`

Фух! Инициализируем это в UnitTestSetupFixture.cs (/Setup/UnitTestSetupFixture.cs):

SURWHFWHG YLUWXDO YRLG ,QLW$XWK6WDQGDUG.HUQHO NHUQHO

^

NHUQHO %LQG +WWS&RRNLH&ROOHFWLRQ! 7R +WWS&RRNLH&ROOHFWLRQ!

NHUQHO %LQG ,$XWK&RRNLH3URYLGHU! 7R )DNH$XWK&RRNLH3URYLGHU! ,Q6LQJOHWRQ6FRS H

NHUQHO %LQG ,$XWKHQWLFDWLRQ! 7R0HWKRG &XVWRP$XWKHQWLFDWLRQ! F !

^

YDUDXWK QHZ&XVWRP$XWKHQWLFDWLRQ

DXWK$XWK&RRNLH3URYLGHU NHUQHO *HW ,$XWK&RRNLH3URYLGHU!

UHWXUQDXWK

`

`

Заметим, что Bind происходит на SingletonScope(), т.е. единожды авторизовавшись в каком­ то тесте, мы в последующих тестах будем использовать эту же авторизацию.

Компилим и пытаемся с этим всем взлететь. Сейчас начнется магия…

Проверка валидации

Если мы просто вызовем что­то типа:

YDUUHJLVWHU8VHU QHZ8VHU9LHZ

^

(PDLO XVHU#VDPSOH FRP

3DVVZRUG

&RQILUP3DVVZRUG

$YDWDU3DWK ILOH QR LPDJH MSJ

%LUWKGDWH'D\

%LUWKGDWH0RQWK

%LUWKGDWH<HDU

&DSWFKD

`

YDUUHVXOW FRQWUROOHU 5HJLVWHU UHJLVWHU8VHU

То, во­первых, никакая неявная валидация не выполнится, а во­вторых, у нас там есть session и мы ее не проинициализировали, она null и всё – ошибка. Так что проверку валидации (та, что в атрибутах) будем устраивать через отдельный класс. Назовем его Валидатор Валидаторович (/Tools/Validator.cs):

SXEOLF FODVV 9DOLGDWRU([FHSWLRQ ([FHSWLRQ

^

SXEOLF9DOLGDWLRQ$WWULEXWH$WWULEXWH ^JHW SULYDWH VHW`

SXEOLF 9DOLGDWRU([FHSWLRQ9DOLGDWLRQ([FHSWLRQ H[ 9DOLGDWLRQ$WWULEXWH DWWULEXWH

EDVHDWWULEXWH *HW7\SH 1DPH H[

^

$WWULEXWH DWWULEXWH

`

`

SXEOLF FODVV 9DOLGDWRU

^

SXEOLF VWDWLF YRLG9DOLGDWH2EMHFW 7! 7 REM

^

YDUW\SH W\SHRI7

YDUPHWD W\SH *HW&XVWRP$WWULEXWHVIDOVH2I7\SH 0HWDGDWD7\SH$WWULEXWH! )LUV W2U'HIDXOW

LIPHWD QXOO

^

W\SH PHWD 0HWDGDWD&ODVV7\SH

`

YDUW\SH$WWULEXWHV W\SH *HW&XVWRP$WWULEXWHVW\SHRI9DOLGDWLRQ$WWULEXWHWUX H2I7\SH 9DOLGDWLRQ$WWULEXWH!

YDUYDOLGDWLRQ&RQWH[W QHZ9DOLGDWLRQ&RQWH[W REM

IRUHDFK YDUDWWULEXWHLQW\SH$WWULEXWHV

^

WU\

^

DWWULEXWH 9DOLGDWH REM YDOLGDWLRQ&RQWH[W

`

FDWFK9DOLGDWLRQ([FHSWLRQ H[

^

WKURZ QHZ9DOLGDWRU([FHSWLRQ H[ DWWULEXWH

`

`

YDUSURSHUW\,QIR W\SH *HW3URSHUWLHV

IRUHDFK YDULQIRLQSURSHUW\,QIR

^

YDUDWWULEXWHV LQIR *HW&XVWRP$WWULEXWHVW\SHRI9DOLGDWLRQ$WWULEXWHWUX H2I7\SH 9DOLGDWLRQ$WWULEXWH!

IRUHDFK YDUDWWULEXWHLQDWWULEXWHV

^

YDUREM3URS,QIR REM *HW7\SH *HW3URSHUW\ LQIR 1DPH

WU\

^

DWWULEXWH 9DOLGDWH REM3URS,QIR *HW9DOXH REMQXOOYDOLGDWLRQ&RQWH [W

`

FDWFK9DOLGDWLRQ([FHSWLRQ H[

^

WKURZ QHZ9DOLGDWRU([FHSWLRQ H[ DWWULEXWH

`

`

`

`

`

Итак, что тут у нас происходит. Вначале мы получаем все атрибуты класса T, которые относятся к типу ValidationAttribute:

YDUW\SH$WWULEXWHV W\SH *HW&XVWRP$WWULEXWHVW\SHRI9DOLGDWLRQ$WWULEXWHWUXH2I7\SH 9DO LGDWLRQ$WWULEXWH!

YDUYDOLGDWLRQ&RQWH[W QHZ9DOLGDWLRQ&RQWH[W REM

IRUHDFK YDUDWWULEXWHLQW\SH$WWULEXWHV

^

WU\

^

DWWULEXWH 9DOLGDWH REM YDOLGDWLRQ&RQWH[W

`

FDWFK9DOLGDWLRQ([FHSWLRQ H[

^

WKURZ QHZ9DOLGDWRU([FHSWLRQ H[ DWWULEXWH

`

`

Потом аналогично для каждого свойства:

YDUSURSHUW\,QIR W\SH *HW3URSHUWLHV

IRUHDFK YDULQIRLQSURSHUW\,QIR

^

YDUDWWULEXWHV LQIR *HW&XVWRP$WWULEXWHVW\SHRI9DOLGDWLRQ$WWULEXWHWUX H2I7\SH 9DOLGDWLRQ$WWULEXWH!

IRUHDFK YDUDWWULEXWHLQDWWULEXWHV

^

YDUREM3URS,QIR REM *HW7\SH *HW3URSHUW\ LQIR 1DPH

WU\

^

DWWULEXWH 9DOLGDWH REM3URS,QIR *HW9DOXH REMQXOOYDOLGDWLRQ&RQWH [W

`

FDWFK9DOLGDWLRQ([FHSWLRQ H[

^

WKURZ QHZ9DOLGDWRU([FHSWLRQ H[ DWWULEXWH

`

`

`

Если валидация не проходит, то происходит исключение, и мы оборачиваем его в ValidatorException, передавая еще и атрибут, по которому произошло исключение. Теперь по поводу капчи и Session. Мы должны контроллеру передать контекст

(MockHttpContext):

YDUFRQWUROOHU 'HSHQGHQF\5HVROYHU &XUUHQW *HW6HUYLFH$UHDV 'HIDXOW &RQWUROOHUV 8VHU&RQWUR OOHU!

YDUKWWS&RQWH[W QHZ0RFN+WWS&RQWH[W 2EMHFW

&RQWUROOHU&RQWH[W FRQWH[W QHZ&RQWUROOHU&RQWH[WQHZ5HTXHVW&RQWH[W KWWS&RQWH[ WQHZ5RXWH'DWD FRQWUROOHU

FRQWUROOHU &RQWUROOHU&RQWH[W FRQWH[W

FRQWUROOHU 6HVVLRQ$GG &DSWFKD,PDJH &DSWFKD9DOXH.H\

И теперь всё вместе:

>7HVW@

SXEOLF YRLG ,QGH[B5HJLVWHU8VHU:LWK'LIIHUHQW3DVVZRUGB([FHSWLRQ&RPSDUH

^

LQLW

YDUFRQWUROOHU 'HSHQGHQF\5HVROYHU &XUUHQW *HW6HUYLFH$UHDV 'HIDXOW &RQWUROOHU V 8VHU&RQWUROOHU!

YDUKWWS&RQWH[W QHZ0RFN+WWS&RQWH[W 2EMHFW

&RQWUROOHU&RQWH[W FRQWH[W QHZ&RQWUROOHU&RQWH[WQHZ5HTXHVW&RQWH[W KWWS&RQWH[ WQHZ5RXWH'DWD FRQWUROOHU

FRQWUROOHU &RQWUROOHU&RQWH[W FRQWH[W

DFW

YDUUHJLVWHU8VHU9LHZ QHZ8VHU9LHZ

^

(PDLO XVHU#VDPSOH FRP

3DVVZRUG

&RQILUP3DVVZRUG

$YDWDU3DWK ILOH QR LPDJH MSJ

%LUWKGDWH'D\

%LUWKGDWH0RQWK

%LUWKGDWH<HDU

&DSWFKD

`

WU\

^

9DOLGDWRU 9DOLGDWH2EMHFW 8VHU9LHZ! UHJLVWHU8VHU9LHZ

`

FDWFK([FHSWLRQ H[

^

$VVHUW ,V,QVWDQFH2I 9DOLGDWRU([FHSWLRQ! H[

$VVHUW ,V,QVWDQFH2I 6\VWHP &RPSRQHQW0RGHO 'DWD$QQRWDWLRQV &RPSDUH$WWULEXWH!

9DOLGDWRU([FHSWLRQ H[$WWULEXWH

`

`

Запускаем, и всё получилось. Но капча проверяется непосредственно в методе контроллера. Специально для капчи:

>7HVW@

SXEOLF YRLG ,QGH[B5HJLVWHU8VHU:LWK:URQJ&DSWFKDB0RGHO6WDWH:LWK(UURU

^

LQLW

YDUFRQWUROOHU 'HSHQGHQF\5HVROYHU &XUUHQW *HW6HUYLFH$UHDV 'HIDXOW &RQWUROOHU V 8VHU&RQWUROOHU!

YDUKWWS&RQWH[W QHZ0RFN+WWS&RQWH[W 2EMHFW

&RQWUROOHU&RQWH[W FRQWH[W QHZ&RQWUROOHU&RQWH[WQHZ5HTXHVW&RQWH[W KWWS&RQWH[ WQHZ5RXWH'DWD FRQWUROOHU

FRQWUROOHU &RQWUROOHU&RQWH[W FRQWH[W

FRQWUROOHU 6HVVLRQ$GG &DSWFKD,PDJH &DSWFKD9DOXH.H\

DFW

YDUUHJLVWHU8VHU9LHZ QHZ8VHU9LHZ

^

(PDLO XVHU#VDPSOH FRP

3DVVZRUG

&RQILUP3DVVZRUG

$YDWDU3DWK ILOH QR LPDJH MSJ

%LUWKGDWH'D\

%LUWKGDWH0RQWK

%LUWKGDWH<HDU

&DSWFKD

`

YDUUHVXOW FRQWUROOHU 5HJLVWHU UHJLVWHU8VHU9LHZ

$VVHUW$UH(TXDOɌɟɤɫɬ ɫ ɤɚɪɬɢɧɤɢ ɜɜɟɞɟɧ ɧɟɜɟɪɧɨFRQWUROOHU 0RGHO6WDWH>&DSWF KD@ (UURUV> @ (UURU0HVVDJH

`

Круто!

Проверка авторизации

Например, мы должны проверить, что, если я захожу не под админом, то в авторизованную часть (в контроллер, помеченный атрибутом [Authorize(Roles=“admin”)]) – обычному польвателю не дадут войти. Есть отличный способ это проверить. Обратим внимание на класс ControllerActionInvoker и отнаследуем его для вызовов

(/Fake/FakeControllerActionInvoker.cs + FakeValueProvider.cs):

SXEOLF FODVV )DNH9DOXH3URYLGHU

^

SURWHFWHG'LFWLRQDU\VWULQJ REMHFW! 9DOXHV ^JHW VHW`

SXEOLF )DNH9DOXH3URYLGHU

^

9DOXHV QHZ'LFWLRQDU\VWULQJ REMHFW!

`

SXEOLF REMHFW WKLV>VWULQJLQGH[@

^

JHW

^

LI9DOXHV &RQWDLQV.H\ LQGH[

^

UHWXUQ9DOXHV>LQGH[@

`

UHWXUQ QXOO

`

VHW

^

LI9DOXHV &RQWDLQV.H\ LQGH[

^

9DOXHV>LQGH[@ YDOXH

`

HOVH

^

9DOXHV$GG LQGH[YDOXH

`

`

`

`

SXEOLF FODVV )DNH&RQWUROOHU$FWLRQ,QYRNHU 7([SHFWHG5HVXOW!&RQWUROOHU$FWLRQ,QYRNHU ZKHUH 7([SHFWHG5HVXOW $FWLRQ5HVXOW

^

SURWHFWHG)DNH9DOXH3URYLGHU )DNH9DOXH3URYLGHU ^JHW VHW`

SXEOLF )DNH&RQWUROOHU$FWLRQ,QYRNHU

^

)DNH9DOXH3URYLGHU QHZ)DNH9DOXH3URYLGHU

`

SXEOLF )DNH&RQWUROOHU$FWLRQ,QYRNHU)DNH9DOXH3URYLGHU IDNH9DOXH3URYLGHU

^

)DNH9DOXH3URYLGHU IDNH9DOXH3URYLGHU

`

SURWHFWHG RYHUULGH $FWLRQ([HFXWHG&RQWH[W,QYRNH$FWLRQ0HWKRG:LWK)LOWHUV&RQWUROOHU&R QWH[W FRQWUROOHU&RQWH[W ,/LVW ,$FWLRQ)LOWHU! ILOWHUV$FWLRQ'HVFULSWRU DFWLRQ'HVFULSWRU , 'LFWLRQDU\VWULQJ REMHFW! SDUDPHWHUV

^

UHWXUQ EDVH,QYRNH$FWLRQ0HWKRG:LWK)LOWHUV FRQWUROOHU&RQWH[W ILOWHUV DFWLRQ'HV FULSWRU SDUDPHWHUV

`

SURWHFWHG RYHUULGH REMHFW *HW3DUDPHWHU9DOXH&RQWUROOHU&RQWH[W FRQWUROOHU&RQWH[W 3D UDPHWHU'HVFULSWRU SDUDPHWHU'HVFULSWRU

^

YDUREM )DNH9DOXH3URYLGHU>SDUDPHWHU'HVFULSWRU 3DUDPHWHU1DPH@

LIREM QXOO

^

UHWXUQREM

`

UHWXUQSDUDPHWHU'HVFULSWRU 'HIDXOW9DOXH

`

SURWHFWHG RYHUULGH YRLG ,QYRNH$FWLRQ5HVXOW&RQWUROOHU&RQWH[W FRQWUROOHU&RQWH[W$FW LRQ5HVXOW DFWLRQ5HVXOW

^

$VVHUW ,V,QVWDQFH2I 7([SHFWHG5HVXOW! DFWLRQ5HVXOW

`

`

По сути это «вызывальщик» action­методов контроллеров, где Generic класс – это ожидаемый класс результата. В случае неавторизации это будет HttpUnauthorizedResult.

Сделаем тест (/Test/Admin/HomeControllerTest.cs):

>7HVW)L[WXUH@

SXEOLF FODVV $GPLQ+RPH&RQWUROOHU7HVW

^

>7HVW@

SXEOLF YRLG ,QGH[B1RW$XWKRUL]H*HW'HIDXOW9LHZB5HGLUHFW7R/RJLQ3DJH

^

YDUDXWK 'HSHQGHQF\5HVROYHU &XUUHQW *HW6HUYLFH ,$XWKHQWLFDWLRQ!

DXWK /RJLQFKHUQLNRY#JPDLO FRP SDVVZRUG IDOVH

YDUKWWS&RQWH[W QHZ0RFN+WWS&RQWH[W DXWK 2EMHFW

YDUFRQWUROOHU 'HSHQGHQF\5HVROYHU &XUUHQW *HW6HUYLFH$UHDV$GPLQ &RQWUROOHU V +RPH&RQWUROOHU!

YDUURXWH QHZ5RXWH'DWD

URXWH 9DOXHV$GGFRQWUROOHU +RPH

URXWH 9DOXHV$GGDFWLRQ ,QGH[

URXWH 9DOXHV$GGDUHD $GPLQ

&RQWUROOHU&RQWH[W FRQWH[W QHZ&RQWUROOHU&RQWH[WQHZ5HTXHVW&RQWH[W KWWS&RQWH[ W URXWH FRQWUROOHU

FRQWUROOHU &RQWUROOHU&RQWH[W FRQWH[W

YDUFRQWUROOHU$FWLRQ,QYRNHU QHZ)DNH&RQWUROOHU$FWLRQ,QYRNHU +WWS8QDXWKRUL]HG5 HVXOW!

YDUUHVXOW FRQWUROOHU$FWLRQ,QYRNHU ,QYRNH$FWLRQ FRQWUROOHU &RQWUROOHU&RQWH[W ,QGH[

`

`

Запускаем тест, он проходит. Сделаем, чтобы авторизация была под пользователем admin и будем ожидать получение ViewResult:

>7HVW@

SXEOLF YRLG ,QGH[B$GPLQ$XWKRUL]HB*HW9LHZ5HVXOW

^

YDUDXWK 'HSHQGHQF\5HVROYHU &XUUHQW *HW6HUYLFH ,$XWKHQWLFDWLRQ!

DXWK /RJLQDGPLQ SDVVZRUG IDOVH

YDUKWWS&RQWH[W QHZ0RFN+WWS&RQWH[W DXWK 2EMHFW

YDUFRQWUROOHU 'HSHQGHQF\5HVROYHU &XUUHQW *HW6HUYLFH$UHDV$GPLQ &RQWUROOHU V +RPH&RQWUROOHU!

YDUURXWH QHZ5RXWH'DWD

URXWH 9DOXHV$GGFRQWUROOHU +RPH

URXWH 9DOXHV$GGDFWLRQ ,QGH[

URXWH 9DOXHV$GGDUHD $GPLQ

&RQWUROOHU&RQWH[W FRQWH[W QHZ&RQWUROOHU&RQWH[WQHZ5HTXHVW&RQWH[W KWWS&RQWH[ W URXWH FRQWUROOHU

FRQWUROOHU &RQWUROOHU&RQWH[W FRQWH[W

YDUFRQWUROOHU$FWLRQ,QYRNHU QHZ)DNH&RQWUROOHU$FWLRQ,QYRNHU 9LHZ5HVXOW!

YDUUHVXOW FRQWUROOHU$FWLRQ,QYRNHU ,QYRNH$FWLRQ FRQWUROOHU &RQWUROOHU&RQWH[W ,QGH[

`

Так же прошли. Молодцом.

На этом давайте остановимся и подумаем, чего мы достигли. Мы можем оттестировать любой контроллер, проверить правильность любой валидации, проверку прав пользователя. Но это касается только контроллера. А как же работа с моделью? Да, мы можем проверить, что вызывается метод репозитория, но на этом всё. Да, мы можем написать Mock­методы для добавления, изменения, удаления, но как это поможет решить ту проблему, о которой я писал вначале главы? Как мы заметим, что что­то не так при упущении поля с тегом? В хрестоматийном примере NerdDinner тесты не покрывают эту область.

Есть IRepository, есть SqlRepository, есть MockRepository. И всё что находится в

SqlRepository – это не покрытая тестами область. А там может быть реализовано очень многое. Что же делать? К чему этот TDD?

Интегрированное тестирование

Идея будет совершенно безумной, мы будем использовать и проверять уже существующий

Соседние файлы в папке ASP.NET MVC Урок 1-F