我有一个cfc,它在很大程度上依赖于Java对象(通过JavaLoader创建)来实现我想要编写一些测试的很多核心功能,我不知道最好的方法是什么。下面是一个我想编写测试的方法示例,其中instance.note是一个java对象。
<cffunction name="getNotes" returntype="Array" access="public" output="false" hint="I return a list of a users notebooks" >
<cfargument name="maxCount" type="numeric" required="false" default="9999" hint="The maximum number of notes to get" />
<cfscript>
if(arguments.maxCount)
return instance.note.listNotes(maxCount);
else
return instance.note.listNotes();
</cfscript>
</cffunction>
我想做的一件事是创建一个存根CFC,它具有相同的方法名称和相似的返回值,然后模拟该存根并注入它?
答案 0 :(得分:3)
难道你不能只对结果写一些有意义的断言,即在音符数组上吗?看看那段代码,我测试的唯一的东西是a)当你传递一个maxCount时,你得到的数组是否尊重这个大小? b)没有maxCount,笔记列表是你期望的长度吗?因为这就是你的所有代码。我测试你的代码,而不是底层java对象的代码。
答案 1 :(得分:2)
当我们需要对依赖于Java对象的CF函数进行单元测试时(我们做了很多),我们使用Mockito来模拟Java对象。
所以,希望这段代码片段有意义,自从我这样做了差不多一年了:
<cfcomponent displayname="TestWhatever" extends="mxunit.framework.TestCase" output="false">
<cffunction name="setUp" access="public" returntype="void">
<cfscript>
// named it mk for keeping it short
variables.mk = createObject("java","org.mockito.Mockito");
//Create the mock object
variables.mockNote = mk.mock(createObject("java","com.company.whatever.note").getClass());
// Mock Data
fullList = {whatever listNotes() returns}
partialList3 = {whatever listNotes(3) returns}
//some common mocking
mk.when(variables.mockNote.listNotes()).thenReturn(fullList);
mk.when(variables.mockNote.listNotes(mk.eq(3))).thenReturn(partialList3);
mk.when(variables.rootOrgObj.guid()).thenReturn("root");
// Assign the mock object to where your CFC expects it.
instance.note = variables.mockNote
</cfscript>
</cffunction>
</cfcomponent>
话虽如此,如果您的样本函数是真实的,那么单元测试真的没有意义。除了作为java对象的代理之外,它根本不做任何事情。那里没有重要的逻辑来测试。
由于你在cfargument上有一个默认值,它将永远存在(再次,我想是这样,自从我完成CF以来已经过了一年),所以你的守护声明甚至不需要 - 第一个代码路径将会总是被调用,如果指定了传递的maxCount,或者如果不是,则调用9999。
答案 2 :(得分:0)
我接受了爱德华的回答并实施了它:
我使用JavaLoader库来创建我的mockito对象。 variables.cfEvernote =“”;
variables.classLoader = createObject("component", "resources.JavaLoader").
init(["#expandPath('../lib/mockito-all-1.8.5.jar')#",
"#expandPath('../lib/CFEvernote.jar')#",
"#expandPath('../lib/libthrift.jar')#",
"#expandPath('../lib/evernote-api-1.18.jar')#"]);
variables.mockito = variables.classLoader.create("org.mockito.Mockito").init();
然后在我的munit测试的setup方法中,我创建了我的新模拟java对象:
<cffunction name="setUp" access="public" output="false" returntype="void">
<cfscript>
variables.cfEvernote = createObject("component","com.714studios.cfevernote.CFEvernote").
Init(variables.configArray[1],variables.configArray[2],
"sandbox.evernote.com",
"http://localhost/cfevernote/callback.cfm"
"#ExpandPath('../lib')#");
variables.mockCFEvernote = variables.mockito.mock(variables.classLoader.create("com.sudios714.cfevernote.CFEvernote").
Init("123","S1","232","sandbox.evernote.com","mock").getClass());
variables.cfEvernote.setCFEvernote(mockCFEvernote);
</cfscript>
然后在我的测试中,我创建了我的模拟行为。
<cffunction name="test..." returntype="void" access="public" output="false" >
<cfscript>
var notebooks = "";
var expected = 12;
var i = 0;
var retArray = createObject("Java","java.util.ArrayList");
var actual = "";
for(i = 1; i lte 12; i = i + 1){
retArray.Add("");
}
variables.mockito.when(mockCFEvernote.listNotebooks(12)).thenReturn(retArray);
notebooks = variables.cfEvernote.getNotebooks(12);
actual = arrayLen(notebooks);
assertEquals(expected,actual);
</cfscript>
我还在这里更详细地写了一篇博客 - http://blog.bittersweetryan.com/2011/07/unit-testing-coldfusion-components-that.html。