OCMock 3 参考
Typorahtml, body {overflow-x: initial !important;}.CodeMirror { height: auto; }
.CodeMirror-scroll { overflow-y: hidden; overflow-x: auto; }
.CodeMirror-lines { padding: 4px 0px; }
.CodeMirror pre { padding: 0px 4px; }
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { background-color: white; }
.CodeMirror-gutters { border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); background-color: rgb(247, 247, 247); white-space: nowrap; }
.CodeMirror-linenumbers { }
.CodeMirror-linenumber { padding: 0px 3px 0px 5px; min-width: 20px; text-align: right; color: rgb(153, 153, 153); }
.CodeMirror div.CodeMirror-cursor { border-left-width: 1px; border-left-style: solid; border-left-color: black; z-index: 3; }
.CodeMirror div.CodeMirror-secondarycursor { border-left-width: 1px; border-left-style: solid; border-left-color: silver; }
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { width: auto; border: 0px; background-color: rgb(119, 238, 119); z-index: 1; background-position: initial initial; background-repeat: initial initial; }
.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite { }
.cm-tab { display: inline-block; }
.cm-s-default .cm-keyword { color: rgb(119, 0, 136); }
.cm-s-default .cm-atom { color: rgb(34, 17, 153); }
.cm-s-default .cm-number { color: rgb(17, 102, 68); }
.cm-s-default .cm-def { color: rgb(0, 0, 255); }
.cm-s-default .cm-variable { color: black; }
.cm-s-default .cm-variable-2 { color: rgb(0, 85, 170); }
.cm-s-default .cm-variable-3 { color: rgb(0, 136, 85); }
.cm-s-default .cm-property { color: black; }
.cm-s-default .cm-operator { color: black; }
.cm-s-default .cm-comment { color: rgb(170, 85, 0); }
.cm-s-default .cm-string { color: rgb(170, 17, 17); }
.cm-s-default .cm-string-2 { color: rgb(255, 85, 0); }
.cm-s-default .cm-meta { color: rgb(85, 85, 85); }
.cm-s-default .cm-qualifier { color: rgb(85, 85, 85); }
.cm-s-default .cm-builtin { color: rgb(51, 0, 170); }
.cm-s-default .cm-bracket { color: rgb(153, 153, 119); }
.cm-s-default .cm-tag { color: rgb(17, 119, 0); }
.cm-s-default .cm-attribute { color: rgb(0, 0, 204); }
.cm-s-default .cm-header { color: blue; }
.cm-s-default .cm-quote { color: rgb(0, 153, 0); }
.cm-s-default .cm-hr { color: rgb(153, 153, 153); }
.cm-s-default .cm-link { color: rgb(0, 0, 204); }
.cm-negative { color: rgb(221, 68, 68); }
.cm-positive { color: rgb(34, 153, 34); }
.cm-header, .cm-strong { font-weight: bold; }
.cm-em { font-style: italic; }
.cm-link { text-decoration: underline; }
.cm-s-default .cm-error { color: rgb(255, 0, 0); }
.cm-invalidchar { color: rgb(255, 0, 0); }
div.CodeMirror span.CodeMirror-matchingbracket { color: rgb(0, 255, 0); }
div.CodeMirror span.CodeMirror-nonmatchingbracket { color: rgb(255, 34, 34); }
.CodeMirror-activeline-background { background-color: rgb(232, 242, 255); background-position: initial initial; background-repeat: initial initial; }
.CodeMirror { position: relative; overflow: hidden; }
.CodeMirror-scroll { margin-bottom: -30px; margin-right: -30px; padding-bottom: 30px; padding-right: 30px; height: 100%; outline: none; position: relative; box-sizing: content-box; }
.CodeMirror-sizer { position: relative; }
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { position: absolute; z-index: 6; display: none; }
.CodeMirror-vscrollbar { right: 0px; top: 0px; overflow-x: hidden; overflow-y: scroll; }
.CodeMirror-hscrollbar { bottom: 0px; left: 0px; overflow-y: hidden; overflow-x: scroll; }
.CodeMirror-scrollbar-filler { right: 0px; bottom: 0px; }
.CodeMirror-gutter-filler { left: 0px; bottom: 0px; }
.CodeMirror-gutters { position: absolute; left: 0px; top: 0px; padding-bottom: 30px; z-index: 3; }
.CodeMirror-gutter { white-space: normal; height: 100%; box-sizing: content-box; padding-bottom: 30px; margin-bottom: -32px; display: inline-block; }
.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; }
.CodeMirror-lines { cursor: text; }
.CodeMirror pre { border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border-width: 0px; background-color: transparent; font-family: inherit; font-size: inherit; margin: 0px; white-space: pre; word-wrap: normal; color: inherit; z-index: 2; position: relative; overflow: visible; background-position: initial initial; background-repeat: initial initial; }
.CodeMirror-wrap pre { word-wrap: break-word; white-space: pre-wrap; word-break: normal; }
.CodeMirror-code pre { border-right-width: 30px; border-right-style: solid; border-right-color: transparent; width: -webkit-fit-content; }
.CodeMirror-wrap .CodeMirror-code pre { border-right-style: none; width: auto; }
.CodeMirror-linebackground { position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 0; }
.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; }
.CodeMirror-widget { }
.CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; }
.CodeMirror-measure { position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden; }
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor { position: absolute; visibility: hidden; border-right-style: none; width: 0px; }
.CodeMirror-focused div.CodeMirror-cursor { visibility: visible; }
.CodeMirror-selected { background-color: rgb(217, 217, 217); background-position: initial initial; background-repeat: initial initial; }
.CodeMirror-focused .CodeMirror-selected { background-color: rgb(215, 212, 240); background-position: initial initial; background-repeat: initial initial; }
.cm-searching { background-color: rgba(255, 255, 0, 0.4); background-position: initial initial; background-repeat: initial initial; }
.CodeMirror span { }
@media print {
.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
}
html { font-size: 14px; }
body { margin: 0px; padding: 0px; height: auto; bottom: 0px; top: 0px; left: 0px; right: 0px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 1rem; line-height: 1.42857143; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255); overflow-x: hidden; }
a:active, a:hover { outline: 0px; }
::selection { background-color: rgb(181, 214, 252); text-shadow: none; background-position: initial initial; background-repeat: initial initial; }
#write { max-width: 854px; margin: 0px auto; height: auto; width: inherit; word-break: normal; word-wrap: break-word; position: relative; white-space: pre-wrap; text-align: justify; padding-bottom: 70px; }
body.typora-export { padding-left: 30px; padding-right: 30px; }
.typora-export #write { margin: 0px auto; }
#write > p:first-child, #write > ul:first-child, #write > pre:first-child, #write > blockquote:first-child, #write > div:first-child { margin-top: 30px; }
img { max-width: 100%; }
input, button, select, textarea { color: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; }
input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }
::before, ::after, * { box-sizing: border-box; }
#write p, #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write div, #write pre { width: inherit; }
h1 { font-size: 2rem; }
p, .mathjax-block { display: block; -webkit-margin-before: 1rem; -webkit-margin-after: 1rem; -webkit-margin-start: 0px; -webkit-margin-end: 0px; }
.hidden { display: none; }
.md-blockmeta { color: rgb(204, 204, 204); font-weight: bold; font-style: italic; }
a { cursor: pointer; }
li span { min-width: 10px; }
#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; margin: 4px 0px 0px; }
tr { page-break-inside: avoid; page-break-after: auto; }
thead { display: table-header-group; }
table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; page-break-inside: auto; }
table.md-table td { min-width: 80px; }
.CodeMirror-placeholder { opacity: 0.3; }
.CodeMirror-code pre { padding: 0px; }
.CodeMirror-lines { padding: 0px; }
div.hr:focus { cursor: none; }
.md-fences, pre.md-fences { font-size: 0.9rem; display: block; page-break-inside: avoid; text-align: left; overflow: visible; white-space: normal; position: relative !important; }
.md-fences.mock-cm { white-space: pre-wrap; }
.footnotes { color: rgb(136, 136, 136); font-size: 0.9rem; padding-top: 1em; padding-bottom: 1em; }
.footnotes + .footnotes { margin-top: -1em; }
sub, sup { line-height: inherit; position: inherit; top: inherit; vertical-align: super; }
.md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; background-color: transparent; text-decoration: none; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 1rem; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; line-height: normal; font-weight: normal; text-align: left; box-sizing: content-box; direction: ltr; background-position: initial initial; background-repeat: initial initial; }
li div { padding-top: 0px; }
blockquote { margin: 1rem 0px; }
li p, li .mathjax-block { margin: 0.5rem 0px; }
li { margin: 0px; }
blockquote > :last-child { margin-bottom: 0px; }
blockquote > :first-child { margin-top: 0px; }
.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; }
@media print {
html, body { height: 100%; }
.typora-export * { -webkit-print-color-adjust: exact; }
}
.footnote-line { margin-top: 0.714em; font-size: 0.7em; }
a img, img a { cursor: pointer; }
#write pre.md-meta-block { font-size: 0.8rem; min-height: 2.86rem; white-space: pre; background-color: rgb(204, 204, 204); display: block; background-position: initial initial; background-repeat: initial initial; }
p > .md-image:only-child { display: inline-block; width: 100%; text-align: center; }
#write .MathJax_Display { margin: 0.8em 0px 0px; }
.mathjax-block { white-space: pre; padding-bottom: 0.65rem; overflow: hidden; width: 100%; }
p + .mathjax-block { margin-top: -1.143rem; }
.mathjax-block:not(:empty)::after { display: none; }
[contenteditable="true"]:active, [contenteditable="true"]:focus { outline: none; box-shadow: none; }
:focus { outline: none; box-shadow: rgb(79, 172, 249) 0px 0px 2px 3px, rgb(120, 174, 218) 0px 0px 2px inset; }
.task-list { list-style-type: none; }
.task-list-item { position: relative; padding-left: 1em; }
.task-list-item input { position: absolute; top: 0px; left: 0px; }
.math { font-size: 1rem; }
.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-top-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; }
.md-toc-content { position: relative; margin-left: 0px; }
.md-toc::after, .md-toc-content::after { display: none; }
.md-toc-item { display: block; color: rgb(65, 131, 196); text-decoration: none; }
.md-toc-inner:hover { text-decoration: underline; }
.md-toc-inner { display: inline-block; cursor: pointer; }
.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: bold; }
.md-toc-h2 .md-toc-inner { margin-left: 2em; }
.md-toc-h3 .md-toc-inner { margin-left: 4em; }
.md-toc-h4 .md-toc-inner { margin-left: 6em; }
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
.md-toc-h6 .md-toc-inner { margin-left: 10em; }
.md-toc-h6 { margin-left: 12em; }
@media screen and (max-width: 48em) {
.md-toc-h3 .md-toc-inner { margin-left: 3.5em; }
.md-toc-h4 .md-toc-inner { margin-left: 5em; }
.md-toc-h5 .md-toc-inner { margin-left: 6.5em; }
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
.md-toc-h6 { margin-left: 9.5em; }
}
a.md-toc-inner { color: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; text-decoration: inherit; line-height: inherit; }
.footnote-line a:not(.reversefootnote) { color: inherit; }
.md-attr { display: none; }
.md-fn-count::after { content: '.'; }
.md-tag { opacity: 0.5; }
h1 .md-tag, h2 .md-tag, h3 .md-tag, h4 .md-tag, h5 .md-tag, h6 .md-tag { font-weight: initial; opacity: 0.35; }
html { font-size: 16px; }
html, body { background-color: rgb(243, 242, 238); font-family: 'PT Serif'; color: rgb(31, 9, 9); line-height: 1.5em; }
#write { max-width: 36em; }
ol, ul { list-style: none; }
blockquote, q { quotes: none; }
blockquote::before, blockquote::after, q::before, q::after { content: none; }
table { border-collapse: collapse; border-spacing: 0px; }
h1, h2, h3, h4, h5, h6 { font-weight: bold; }
h1 { font-size: 1.875em; line-height: 1.6em; margin-top: 2em; }
h2, h3 { font-size: 1.3125em; line-height: 1.15; margin-top: 2.285714em; margin-bottom: 1.15em; }
h3 { font-weight: normal; }
h4 { font-size: 1.125em; margin-top: 2.67em; }
h5, h6 { font-size: 1em; }
h1 { border-bottom-width: 1px; border-bottom-style: solid; margin-bottom: 1.875em; padding-bottom: 0.8125em; }
a { text-decoration: none; color: rgb(6, 85, 136); }
a:hover, a:active { text-decoration: underline; }
p, blockquote, pre.md-fences, .md-fences { margin-bottom: 1.5em; }
h1, h2, h3, h4, h5, h6 { margin-bottom: 1.5em; }
blockquote { font-style: italic; border-left-width: 5px; border-left-style: solid; margin-left: 2em; padding-left: 1em; }
ul, ol { margin: 0px 0px 1.5em 1.5em; }
ol li { list-style-type: decimal; list-style-position: outside; }
ul li { list-style-type: disc; list-style-position: outside; }
.md-meta, .md-before, .md-after { color: rgb(153, 153, 153); }
table { margin-bottom: 1.5em; font-size: 1em; }
thead th, tfoot th { padding: 0.25em 0.25em 0.25em 0.4em; text-transform: uppercase; }
th { text-align: left; }
td { vertical-align: top; padding: 0.25em 0.25em 0.25em 0.4em; }
code, pre.md-fences { background-color: rgb(218, 218, 218); padding-left: 1ch; padding-right: 1ch; }
pre.md-fences { margin-left: 2em; margin-bottom: 3em; }
pre, code, tt { font-size: 0.875em; line-height: 1.714285em; }
h1 { line-height: 1.3em; font-weight: normal; margin-bottom: 0.5em; }
p + ul, p + ol { margin-top: -1em; }
h3 + ul, h4 + ul, h5 + ul, h6 + ul, h3 + ol, h4 + ol, h5 + ol, h6 + ol { margin-top: 0.5em; }
li > ul, li > ol { margin-top: inherit; }
h2, h3 { margin-bottom: 0.75em; }
hr { border-style: none none solid; border-bottom-width: 1px; }
h1 { border-color: rgb(197, 197, 197); }
blockquote { border-color: rgb(186, 186, 186); color: rgb(101, 101, 101); }
thead.md-table-edit { background-color: transparent; }
thead { background-color: rgb(218, 218, 218); }
tr:nth-child(even) { background-color: rgb(232, 231, 231); background-position: initial initial; background-repeat: initial initial; }
hr { border-color: rgb(197, 197, 197); }
.task-list { padding-left: 1rem; }
.task-list-item { padding-left: 1.5rem; list-style-type: none; }
.task-list-item input::before { content: '√'; display: inline-block; width: 1.25rem; height: 1.5rem; vertical-align: middle; text-align: center; color: rgb(221, 221, 221); background-color: rgb(243, 242, 238); }
.task-list-item input:checked::before, .task-list-item input[checked]::before { color: inherit; }
#write pre.md-meta-block { min-height: 1.875rem; color: rgb(85, 85, 85); border: 0px; background-color: transparent; margin-left: 1em; margin-top: 1em; background-position: initial initial; background-repeat: initial initial; }
.md-image > .md-meta { color: rgb(155, 81, 70); }
.md-expand.md-image > .md-meta { background-color: rgba(255, 255, 255, 0.65098); }
.md-image > .md-meta { font-family: Menlo, 'Ubuntu Mono', Consolas, 'Courier New', 'Microsoft Yahei', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', sans-serif; }
#write > h3.md-focus::before { left: -2.5rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
#write > h4.md-focus::before { left: -2.5rem; top: 0.25rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
#write > h5.md-focus::before { left: -2.5rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
#write > h6.md-focus::before { left: -2.5rem; top: 0.3125rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
.md-toc:focus .md-toc-content { margin-top: 19px; }
.md-toc-content:empty::before { color: rgb(6, 85, 136); }
.md-toc-item { color: rgb(6, 85, 136); }
#write div.md-toc-tooltip { background-color: rgb(243, 242, 238); }
#outline-dropmenu { background-color: rgb(243, 242, 238); -webkit-box-shadow: rgba(0, 0, 0, 0.372549) 0px 6px 12px; box-shadow: rgba(0, 0, 0, 0.372549) 0px 6px 12px; }
.pin-outline #outline-dropmenu { background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; box-shadow: none; border-right-width: 1px; border-right-style: dashed; background-position: inherit inherit; background-repeat: inherit inherit; }
.pin-outline #outline-dropmenu:hover .outline-title-wrapper { border-left-width: 1px; border-left-style: dashed; }
.outline-item:hover { background-color: rgb(218, 218, 218); border-left-width: 18px; border-left-style: solid; border-left-color: rgb(218, 218, 218); border-right-width: 18px; border-right-style: solid; border-right-color: rgb(218, 218, 218); }
.outline-expander::before { content: ''; font-family: FontAwesome; font-size: 14px; top: 1px; }
.outline-expander:hover::before, .outline-item-open > .outline-item > .outline-expander::before { content: ''; }
OCMock 3 参考1.创建Mock对象1.1 类Mock1.2 协议Mock1.3 严格的类和协议Mock1.4 部分Mock1.5 观察者Mock2 置换方法2.1 置换方法(待置换的方法返回objects)2.2 置换方法(待置换的方法返回values)2.3 委托到另一个方法(置换委托方法到另外一个方法)2.4 置换一个blcok方法.2.5 置换方法的参数2.6 调用某个方法就抛出异常2.7 调用某个方法就发送通知2.8 链式调用2.9 转发的原来的对象/类2.10 什么也不做3 验证作用3.1 运行后就验证3.2 置换后验证4 参数约束4.1 任意参数约束4.2 忽略非对象的参数4.3 匹配参数4.4 使用Hamcrest来匹配5 类方法的Mock5.1 置换类方法5.2 验证类方法的调用5.3 有歧义的类方法和实例方法5.4 恢复类6 部分Mock6.1 置换方法6.2 验证方法调用6.3 恢复对象7 严格mock和期望7.1 Expect-run-verify 期望-运行-验证7.2 严格的mock 和快速失败7.3 置换操作和预期7.4 延时验证7.5 依序验证8 观察者mock8.1 准备工作8.2 验证9 进阶话题9.1 对于普通的mock,快速失败9.2 在OCMVerifyAll时重新抛出异常9.3 置换创建对象的方法9.4 基于实例对象的方法替换10 使用限制10.1 在一个指定的类上,只能有一个mock对象10.2 在被置换的方法上设置期望,会不起作用10.3 Partial mock 不能在某些特定的类使用10.4 某些特定的类不能被置换和验证10.5 NSString的类方法不能被置换和验证10.6 NSObject 的方法不能被验证10.7 apple 的私有方法不能被验证10.8 Verify-after-running不能使用延时
OCMock 3 参考
1.创建Mock对象
1.1 类Mock
id classMock = OCMClassMock([SomeClass class]);
1.2 协议Mock
id protocolMock = OCMProtocolMock(@protocol(SomeProtocol));
1.3 严格的类和协议Mock
默认的mock方式是nice(方法调用的时候返回nil或者是返回正确的方法)
严格的模式下,mock的对象在调用没有被stub(置换)的方法的时候,会抛出异常.
id classMock = OCMStrictClassMock([SomeClass class]);id protocolMock = OCMStrictProtocolMock(@protocol(SomeProtocol));
1.4 部分Mock
id partialMock = OCMPartialMock(anObject)
这样创建的对象在调用方法时:
- 如果方法被stub,调用stub后的方法.
- 如果方法没有被stub,调用原来的对象的方法.
partialMock 对象在调用方法后,可以用于稍后的验证此方法的调用情况(被调用,调用结果)
1.5 观察者Mock
id observerMock = OCMObserverMock();
这样创建的对象可以用于观察/通知.
2 置换方法
2.1 置换方法(待置换的方法返回objects)
OCMStub([mock someMethod]).andReturn(anObject);
在mock对象上调用某个方法的时候,这个方法一定返回一个anObject.(也就是说强制替换了某个方法的返回值为anObject)
2.2 置换方法(待置换的方法返回values)
OCMStub([mock aMethodReturningABoolean]).andReturn(YES);
在mock对象上调用某个方法的时候,这个方法一定返回values.
注意这里的原始值类型一定要和原来的方法的返回值一致.
2.3 委托到另一个方法(置换委托方法到另外一个方法)
OCMStub([mock someMethod]).andCall(anotherObject, @selector(aDifferentMethod));
置换mock 对象的someMethod ==> anotherObject 的aDifferentMethod.
这样,当mock对象调用someMethod方法的时候,实际上的操作就是anotherObject 调用了aDifferentMethod方法.
2.4 置换一个blcok方法.
OCMStub([mock someMethod]).andDo(^(NSInvocation *invocation) { /* block that handles the method invocation */ });
在mock对象调用someMethod的时候,andDo后面的block会调用.block可以从NSInvocation中得到一些参数,然后使用这个NSInvocation对象来构造返回值等等.
2.5 置换方法的参数
OCMStub([mock someMethodWithReferenceArgument:[OCMArg setTo:anObject]]);
OCMStub([mock someMethodWithReferenceArgument:[OCMArg setToValue:OCMOCK_VALUE((int){aValue})]]);
mock对象在调用某个带参数的方法的时候,这个方法的参数可以被置换.
setTo用来设置对象参数,setToValue用来设置原始值类型的参数.
2.6 调用某个方法就抛出异常
OCMStub([mock someMethod]).andThrow(anException);
当mock对象调用someMethod的时候,就会抛出异常
2.7 调用某个方法就发送通知
OCMStub([mock someMethod]).andPost(aNotification);
当mock对象调用someMethod的时候,就会发送通知.
2.8 链式调用
OCMStub([mock someMethod]).andPost(aNotification).andReturn(aValue);
所有的actions(比如andReturn,andPost)可以链式调用.上面的例子中,mock对象调用someMethod方法后,发送通知,返回aValue
2.9 转发的原来的对象/类
OCMStub([mock someMethod]).andForwardToRealObject();
使用部分mock的时候,使用类方法的可以转发到原来的对象/原来的类.
这个功能在链式调用或者是使用expectation的时候很有用.
2.10 什么也不做
OCMStub([mock someMethod]).andDo(nil);
可以给andDo传入nil参数,而不是原来一个block作为参数.
这个功能在使用部分mock/mock类的时候很有用,可以屏蔽原来的行为.
3 验证作用
3.1 运行后就验证
id mock = OCMClassMock([SomeClass class]);/* run code under test */OCMVerify([mock someMethod]);
在mock对象调用someMethod后就开始验证.(如果这个方法没有被调用),就抛出一个错误.
在验证语句中可以使用 参数约束.
3.2 置换后验证
id mock = OCMClassMock([SomeClass class]);OCMStub([mock someMethod]).andReturn(myValue);/* run code under test */OCMVerify([mock someMethod]);
在置换某个方法(置换了返回的参数)后,然后可以验证这个方法是否被调用.
4 参数约束
4.1 任意参数约束
OCMStub([mock someMethodWithAnArgument:[OCMArg any]])OCMStub([mock someMethodWithPointerArgument:[OCMArg anyPointer]])OCMStub([mock someMethodWithSelectorArgument:[OCMArg anySelector]])
不管传递什么参数,对于所有活跃的invocations,置换该方法.Pointers 和selectors 需要像上面一样特殊对待.对于既不是对象,也不是指针,更不是SEL类型的,不可以忽略的参数,可以使用 any 来代替.
4.2 忽略非对象的参数
[[[mock stub] ignoringNonObjectArgs] someMethodWithIntArgument:0]
在这个invocation中,mock忽略所有的非对象参数.mock对象将会接收所有的someMethodWithIntArgument 方法 invocation,而不去管实际传递进来的参数是什么.如果这个方法含有对象参数和非对象参数,对象参数仍然可以使用OCMArg的参数约束.
4.3 匹配参数
OCMStub([mock someMethod:aValue)OCMStub([mock someMethod:[OCMArg isNil]])OCMStub([mock someMethod:[OCMArg isNotNil]])OCMStub([mock someMethod:[OCMArg isNotEqual:aValue]])OCMStub([mock someMethod:[OCMArg isKindOfClass:[SomeClass class]]])OCMStub([mock someMethod:[OCMArg checkWithSelector:aSelector onObject:anObject]])OCMStub([mock someMethod:[OCMArg checkWithBlock:^BOOL(id value) { /* return YES if value is ok */ }]])
如果在置换创建的时候,有个一个参数传递进来了,置换方法将仅仅匹配精确参数的invocations.带不同的参数来调用的方法不会被匹配.
OCMArg类提供了几个不同的方法来匹配不同的参数类型.
对于checkWithSelector:onObject:方法, 当mock对象接收到someMethod:的时候, 会触发 anObject上的aSelector方法. 如果方法带参数,这个参数会传递给someMethod:. 这个方法应该返回一个BOOL值,表示这个参数是否和预期的一样.
4.4 使用Hamcrest来匹配
OCMStub([mock someMethod:startsWith(@"foo")]
OCMock不带 Hamcrest 框架,所以如果想要使用的话,需要自己安装Hamcrest .
5 类方法的Mock
5.1 置换类方法
id classMock = OCMClassMock([SomeClass class]);OCMStub([classMock aClassMethod]).andReturn(@"Test string");// result is @"Test string"NSString *result = [SomeClass aClassMethod];
置换类方法和置换实例方法的步骤相像.但是mock对象在深层次上对原有 类做了些更改.(替换了原有的的类的meta class).这让置换调用直接作用在mock对象上,而不是原有的类.
注意:
添加到类方法上的mock对象跨越了多个测试,mock的类对象在置换后不会deallocated,需要手动来取消这个mock关系.
如果mock对象作用于同一个类, 这时的行为就不预测了.
5.2 验证类方法的调用
id classMock = OCMClassMock([SomeClass class]);/* run code under test */OCMVerify([classMock aClassMethod]);
验证类方法的调用和验证实例方法的调用的使用方式一样.
5.3 有歧义的类方法和实例方法
id classMock = OCMClassMock([SomeClass class]);OCMStub(ClassMethod([classMock ambiguousMethod])).andReturn(@"Test string");// result is @"Test string"NSString *result = [SomeClass ambiguousMethod];
置换了类方法,但是类有一个和类方法同名的实例方法,置换类方法的时候,必须使用ClassMethod()
5.4 恢复类
id classMock = OCMClassMock([SomeClass class]);/* do stuff */[classMock stopMocking];
置换类方法后,可以将类恢复到原来的状态,通过调用stopMocking来完成.
如果在结束测试前,需要恢复到原来的状态的话,这就很有用了.
在mock对象被释放的时候,stopMocking会自动调用.
当类恢复到原来的对象,类对象的meta class会变为原来的meta class.这会移除所有的方法置换.
在调用了stopMocking之后,不应该继续使用mock对象.
6 部分Mock
6.1 置换方法
id partialMock = OCMPartialMock(anObject);OCMStub([partialMock someMethod]).andReturn(@"Test string");// result1 is @"Test string"NSString *result1 = [partialMock someMethod];// result2 is @"Test string", too!NSString *result2 = [anObject someMethod];
部分Mock修改了原有的mock对象的类.(实际上是继承了待mock对象,然后替换用 继承的类来代替原有的类).
这就是说: 使用真实的对象来调用,即使是使用self,也会影响 置换方法和预期的结果.
6.2 验证方法调用
id partialMock = OCMPartialMock(anObject);/* run code under test */OCMVerify([partialMock someMethod]);
验证方法的调用和验证类方法,验证协议的调用类似.
6.3 恢复对象
id partialMock = OCMPartialMock(anObject);/* do stuff */[partialMock stopMocking];
真正的对象可以通过调用stopMocking方法来恢复到原来的状态.
这种情况只有在结束测试之前需要恢复到原来状态.
部分mock对象会在释放的时候,会自动调用 stopMocking方法.
当对象转变为原来的状态后,类会变为原来的类.也会移除所有的置换方法.
在调用了stopMocking之后,最好不要去使用mock对象.
7 严格mock和期望
7.1 Expect-run-verify 期望-运行-验证
id classMock = OCMClassMock([SomeClass class]);OCMExpect([classMock someMethodWithArgument:[OCMArg isNotNil]]);/* run code under test, which is assumed to call someMethod */OCMVerifyAll(classMock)
这是使用mock最原始的方法:
- 创建mock对象
- 期望调用某个方法
- 测试代码(预想的是这段测试代码会调用上面期望调用的方法.
- 验证mock对象(也就是验证期望的方法是否被调用了)
如果预期的方法没有被调用,或者调用的时候,传递的参数不对,那么就好产生错误.可以使用上面 参数约束.
严格的mock可以用在类和协议上.
如果有怀疑的话,可以使用 3 验证作用
7.2 严格的mock 和快速失败
id classMock = OCMStrictClassMock([SomeClass class]);[classMock someMethod]; // this will throw an exception
上面mock没有设置任何期望,直接掉调用某个方法会抛出异常.
当超出去预期的调用的时候,会立即测试失败. 只有strict mock才会快速失败.
7.3 置换操作和预期
xid classMock = OCMStrictClassMock([SomeClass class]);OCMExpect([classMock someMethod]).andReturn(@"a string for testing");/* run code under test, which is assumed to call someMethod */OCMVerifyAll(classMock)
可以使用andReturn,andThrow,等预期的操作.如果方法被调用,会调用置换 方法,确认方法确实被调用了.
7.4 延时验证
xxxxxxxxxxid mock = OCMStrictClassMock([SomeClass class]);OCMExpect([mock someMethod]);/* run code under test, which is assumed to call someMethod eventually */OCMVerifyAllWithDelay(mock, aDelay);
在某种情况下,预期的方法只有在 run loop 出于活跃状态的时候才会被调用.这时,可以将认证延时一会.aDelay是mock对象会等待的最大时间.通常情况下,在预期达到后就会返回.
7.5 依序验证
id mock = OCMStrictClassMock([SomeClass class]);[mock setExpectationOrderMatters:YES];OCMExpect([mock someMethod]);OCMExpect([mock anotherMethod]);// calling anotherMethod before someMethod will cause an exception to be thrown[mock anotherMethod];
mock会按照在预期中设置好的顺序来判断.只要调用的不是按照期望的调用顺序,这个时候就会抛出异常.
8 观察者mock
8.1 准备工作
xid observerMock = OCMObserverMock();[notificatonCenter addMockObserver:aMock name:SomeNotification object:nil];[[mock expect] notificationWithName:SomeNotification object:[OCMArg any]];
- 为观察者和通知创建一个mock对象.
- 在通知中心注册对象
- 预期会调用这个通知.
8.2 验证
xxxxxxxxxxOCMVerifyAll(observerMock);
目前观察者 mock 总是严格的mock.当一个不在预期中的通知调用的时候,就会抛出一个异常.
这就是说,单个的通知实际上不是能被验证的.所有的通知必须按照预期赖设置.他们会在通过调用OCMVerifyAll来一起验证.
9 进阶话题
9.1 对于普通的mock,快速失败
对strict mock 对象,在一个mock对象上调用没有被mock方法(没有被置换)的时候,会抛出一个异常,这时候会发生 快速失败.
xid mock = OCMClassMock([SomeClass class]);[[mock reject] someMethod];
这种情况下,mock会接受除了someMethod 的所有方法.触发someMethod方法会导致快速失败.
9.2 在OCMVerifyAll时重新抛出异常
在fail-fast的时候会抛出异常,但是这并不一定会导致测试失败.
通过调用OCMVerifyAll重新抛出异常可以导致测试失败.
这个功能在不在预期中的从notifications引发的invocations出现的时候使用.
9.3 置换创建对象的方法
id classMock = OCMClassMock([SomeClass class]);OCMStub([classMock copy])).andReturn(myObject);
可以置换创建对象的 类/实例方法.当被置换的方法以 alloc,new,copy,mutableCopy开头的方法时,OCMock会自动调整对象的引用计数.
id classMock = OCMClassMock([SomeClass class]);OCMStub([classMock new])).andReturn(myObject);
尽管可以置换类的new方法,但是不建议这么做.
没有办法置换 init 方法,因为这个方法是被mock对象自己实现的.
9.4 基于实例对象的方法替换
id partialMock = OCMPartialMock(anObject);OCMStub([partialMock someMethod]).andCall(differentObject, @selector(differentMethod));
用一句话概括起来,Method swizzling 会在运行时替换一个方法的实现.
使用 partial mock然后调用 andCall操作可以实现这个方法替换.
当anObject收到someMethod消息时,anObject的实现没有触发,相反的,
differentObject的differentMethod得到调用.
其他方法并不会收到影响,仍然会调用原来的的方法的实现.
10 使用限制
10.1 在一个指定的类上,只能有一个mock对象
xxxxxxxxxx// don't do thisid mock1 = OCMClassMock([SomeClass class]);OCMStub([mock1 aClassMethod]);id mock2 = OCMClassMock([SomeClass class]);OCMStub([mock2 anotherClassMethod]);
原因是类的meta class 替换后,不会释放,mock类仍会存在,甚至可能跨tests.
如果多个相同mock对象管理同一个类,运行时的行为就不可确定.
10.2 在被置换的方法上设置期望,会不起作用
id mock = OCMStrictClassMock([SomeClass class]);OCMStub([mock someMethod]).andReturn(@"a string");OCMExpect([mock someMethod]);/* run code under test */OCMVerifyAll(mock); // will complain that someMethod has not been called
上面代码先替换了someMethod,然后强制someMethod返回”a string"
由于现在mock的实现,所有的someMethod都会置换所处理.所以,即使这个方法被调用,这个验证也会失败.
可以通过在expect后添加andReturn来避免这个问题. 也可以通过在expect后再次设置一个方法替换.
10.3 Partial mock 不能在某些特定的类使用
xid partialMockForString = OCMPartialMock(@"Foo");// will throw an exceptionNSDate *date = [NSDate dateWithTimeIntervalSince1970:0];id partialMockForDate = OCMPartialMock(date);// will throw on some architectures
不可能创建一个 toll-free bridged的类,例如 NSString,或者是NSDate.
如果你试图这么去做,那么可能会抛出一个异常.
10.4 某些特定的类不能被置换和验证
id partialMockForString = OCMPartialMock(anObject);OCMStub([partialMock class]).andReturn(someOtherClass); // will not work
不能mock某些运行时的方法,例如
- class,
- methodSignatureForSelector:
- forwardInvocation:
10.5 NSString的类方法不能被置换和验证
id stringMock = OCMClassMock([NSString class]);// the following will not workOCMStub([stringMock stringWithContentsOfFile:[OCMArg any] encoding:NSUTF8StringEncoding error:[OCMArg setTo:nil]]);
10.6 NSObject 的方法不能被验证
xxxxxxxxxxid mock = OCMClassMock([NSObject class]);/* run code under test, which calls awakeAfterUsingCoder: */OCMVerify([mock awakeAfterUsingCoder:[OCMArg any]]);// still fails
不可能在NSObject 和它的分类category上使用verify-after-running.
在某些情况下可能置换这个方法,然后验证.
10.7 apple 的私有方法不能被验证
xxxxxxxxxxUIWindow *window = /* get window somehow */id mock = OCMPartialMock(window);/* run code under test, which causes _sendTouchesForEvent: to be invoked */OCMVerify([mock _sendTouchesForEvent:[OCMArg any]]);// still fails
含有下划线前缀,后缀,NS,UI开头的方法等.
10.8 Verify-after-running不能使用延时
只有在 严格的mock和期望中,可以使用expect-run-verify
OCMock 3 参考的更多相关文章
- Podfile语法参考(译)
https://www.jianshu.com/p/8af475c4f717 2015.10.30 19:14* 字数 2496 阅读 35976评论 9喜欢 120 本文翻译自官方的Podfile ...
- Xcode 5 单元测试(二)OCMock和GHUnit
在Xcode 5 单元测试(一)使用XCTest进行单元测试中说了如何在Xcode 5中使用XCTest进行简单的单元测试,本文就来探讨下mock测试和更高级的工具GHUnit. Mock 首先科普下 ...
- Hyper-v 安装CentOS 7 (其他虚拟机一样参考)
平台之大势何人能挡? 带着你的Net飞奔吧!http://www.cnblogs.com/dunitian/p/4822808.html hyper-v安装很多人没弄过,我这里介绍一下.(其他虚拟机参 ...
- ifconfig: command not found(CentOS专版,其他的可以参考)
ifconfig: command not found 查看path配置(echo相当于c中的printf,C#中的Console.WriteLine) echo $PATH 解决方案1:先看看是不是 ...
- 参考bootstrap中的popover.js的css画消息弹框
前段时间小颖的大学同学给小颖发了一张截图,图片类似下面这张图: 小颖当时大概的给她说了下,其实小颖也不知道上面那个三角形怎么画嘻嘻,给她说了DOM结构,具体的css让她自己百度,今天小颖自己参考boo ...
- Oracle安装部署,版本升级,应用补丁快速参考
一.Oracle安装部署 1.1 单机环境 1.2 Oracle RAC环境 1.3 Oracle DataGuard环境 1.4 主机双机 1.5 客户端部署 二.Oracle版本升级 2.1 单机 ...
- Angularjs参考框架地址
1.Table(Grid)参考地址 https://github.com/samu/angular-table https://github.com/daniel-nagy/md-data-table ...
- iOS开发之三个Button实现图片无限轮播(参考手机淘宝,Swift版)
这两天使用Reveal工具查看"手机淘宝"App的UI层次时,发现其图片轮播使用了三个UIButton的复用来实现的图片循环无缝滚动.于是乎就有了今天这篇博客,看到“手机淘宝”这个 ...
- SQL 性能调优中可参考的几类Lock Wait
在我们的系统出现性能问题时,往往避不开调查各种类型 Lock Wait,如Row Lock Wait.Page Lock Wait.Page IO Latch Wait等.从中找出可能的异常等待,为性 ...
随机推荐
- 关于VC++的增量链接(Incremental Linking)
增量链接(Incremental Linking)这个词语在使用Visual C++时经常会遇到(其实不只是VS系列,其它链接器也有这个特性), 就比如经常遇到的:上一个增量链接没有生成它, 正在执行 ...
- /usr 的由来及/usr目录结构 [转]
一直好奇包罗众多程序的usr目录为什么叫usr呢?usr到底是什么的缩写,终于找到比较靠谱的答案了 /usr 的由来及/usr目录结构 作者 AN SHEN| 发布于 2011-11-05 在 lin ...
- gcc cc1: all warnings being treated as errors
cc1: all warnings being treated as errors 在Makefile中找到 -Werror项,删除即可.删除后重新编译. 或设置环境变量 c工程设置 export C ...
- json解析为泛型对象
一.方法 public <T> T jsonToObjByType(String str, Type type) { try { if (isValidJson(str)) { retur ...
- Java 泛型(Generics) 综述
一. 引子 一般的类和方法.仅仅能使用详细类型:要么是基本类型.要么是自己定义类型.假设要编写能够应用于多种类型的代码,这样的刻板的限制对代码的束缚就会非常大. 多态算是一种泛化机制,但对代码的约束还 ...
- Using ADB and fastboot
What is adb? The Android Debug Bridge (adb) is a development tool that facilitates communication bet ...
- springboot + mybatis-pagehelper 参数查询不分页的bug。。。
mmp,搞了很久 官方git上给出的配置是这样的: 这样做分页,如果仅仅支持一个查询,没问题,但是如果你带参数查询了,那就分页会出问题 把这行注释了即可 reasonable是指的让分页更加的合理化, ...
- Shiro系列(1) - 权限管理的介绍与原理
1. 什么是权限管理 一般来说,只要有用户参与,那么该系统都会需要权限管理,权限管理实现了对用户访问系统 指定功能的限制,按照管理员定义的安全规则或权限策略,限制用户只能访问自己被授权的那些资源路径 ...
- 5. MIZ7035 PCIe测试 RIFFA【PCIE视频传输】
1.前言 MIZ7035官方提供了两种pcie的demo,一个就是普通的PIO测试,一个是BMD测试.我只是试验了PIO功能,可以对板卡直接进行IO寄存器读写.而另外一个BMD功能使用了DMA来加速数 ...
- 【Unity】4.0 第4章 创建基本的游戏场景
分类:Unity.C#.VS2015 创建日期:2016-04-05 一.简介 上一章我们学习了如何利用长方体(Cube)制作基本的3D模型,以及如何导入各种资源,本章将在此基础上,分别制作路面.跳板 ...