Каков наилучший способ модульного тестирования cfc, который использует Java-объект для большей функциональности? - PullRequest
4 голосов
/ 14 июля 2011

У меня есть 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-заглушку с такими же именами методов и схожими возвращаемыми значениями, а затем высмеивать эту заглушку и вводить ее?

Ответы [ 3 ]

3 голосов
/ 14 июля 2011

Разве вы не можете просто написать значимые утверждения о результате, то есть о массиве заметок?Глядя на этот код, единственное, что я проверю, это: а) когда вы передаете maxCount, соответствует ли ваш результирующий массив этому размеру?б) без maxCount, список заметок длина, которую вы ожидаете?Потому что это все, что делает ваш код.Я бы протестировал ваш код, а не код базового Java-объекта.

2 голосов
/ 15 июля 2011

Когда нам нужно было выполнить модульное тестирование функций CF, которые опирались на объекты Java (которых мы сделали МНОГО), мы использовали 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), так что вашоператор guard даже не требуется - всегда будет вызываться первый путь кода, с переданным maxCount, если он указан, или с 9999, если нет.

0 голосов
/ 19 июля 2011

Я взял ответ Эдварда и реализовал его так:

Я использовал библиотеку 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 я создаю свой новый фиктивный объект 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.

...