Генерация JavaScript в C # и последующее тестирование - PullRequest
4 голосов
/ 13 апреля 2010

В настоящее время мы разрабатываем приложение ASP.NET MVC, которое интенсивно использует метаданные на основе атрибутов для генерации JavaScript.

Ниже приведен пример типа методов, которые мы пишем:

function string GetJavascript<T>(string javascriptPresentationFunctionName,
                                 string inputId,
                                 T model)
{
    return @"function updateFormInputs(value){
        $('#" + inputId + @"_SelectedItemState').val(value);
        $('#" + inputId + @"_Presentation').val(value);
     }

    function clearInputs(){
        " + helper.ClearHiddenInputs<T>(model) + @"
        updateFormInputs('');
    }

    function handleJson(json){
        clearInputs();
        " + helper.UpdateHiddenInputsWithJson<T>("json", model) + @"
        updateFormInputs(" + javascriptPresentationFunctionName + @"());
        " + model.GetCallBackFunctionForJavascript("json") + @"
    }";
}

Этот метод генерирует некоторую рабочую среду и передает различные другие методы, которые возвращают строки. Затем весь лот возвращается в виде строки и записывается на выход.

У меня есть следующие вопросы:

1) Есть ли лучший способ сделать это, кроме использования больших блоков строк?

Мы рассмотрели возможность использования StringBuilder или потока ответов, но он выглядит довольно «шумным». Использование string.format становится трудным для понимания.

2) Как бы вы провели модульное тестирование этого кода? Кажется, немного любитель просто делает сравнение строк в поисках определенного вывода в строке.

3) Как на самом деле тестировать возможный вывод JavaScript?

Спасибо за ваш вклад!

Ответы [ 4 ]

2 голосов
/ 08 сентября 2010

Мы создали библиотеку специально для того, чтобы встроить JavaScript-код в похожий синтаксис в наш код C #, а затем сделали его открытым исходным кодом.

Посмотрите на Adam.JSGenerator .

1 голос
/ 13 апреля 2010

Если вы не заботитесь о суперской производительности, вы можете использовать язык шаблонов для генерации JavaScript.

Тогда для модульного тестирования вы просто заполняете шаблоны соответствующими привязками / переменными и затем запускаете его через оценщик Javascript, такой как Rhino, или любой другой эквивалентный .NET, по крайней мере, для проверки синтаксиса, если не фактического кода JS.

Кроме этого, я бы серьезно усомнился в разработке программного обеспечения, которое генерирует Javascript следующим образом. Также похоже, что вы используете JQuery, но ссылаетесь на $ напрямую, что может привести к некоторым проблемам в будущем.

Если компиляторы, генерирующие Javascript, это одно (аля GWT), но я бы максимально отделил ваш JS-код на стороне клиента от вашего .NET-кода (не говоря уже о том, что ваш .NET-код выглядит так, как будто JS на стороне сервера говорит о путанице).

Этот модный дизайн отделения клиентского дерьма от сервера известен как SOFEA. Я позволю тебе гуглить это.

1 голос
/ 13 апреля 2010

Я обычно пытаюсь создать отдельный файл .js для большей части / всего моего кода JavaScript. Обычно мне нужно, чтобы общий bahvior применялся ко многим элементам, которые динамически создаются элементами управления ASP или кодом на стороне сервера, поэтому я не смогу все кодировать в файл .js.

Я обнаружил, что основная причина, по которой вы хотите сгенерировать javascript на сервере, заключается в том, что вы не будете знать идентификаторы элементов, пока страница не отобразится. Поэтому я стараюсь максимально сократить эту зависимость, чтобы генерировать как можно меньше javascript. Например, в традиционном ASP.Net (не MVC), если бы я рендерил набор форм, таких как в примере, каждое с несколькими полями, то я, вероятно, имел бы что-то в этом коде, например:

protected void FormRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    Control form = e.Item.FindControl("MyForm");
    ClientScript.RegisterStartupScript(this.GetType(), "prepareForm_" + form.ClientID, @"prepareForm('" + form.ClientID + "');", true);
}

Отдельный файл .js будет содержать определение функции prepareForm, которое будет выглядеть примерно так:

// define a formPresenter "class" that encapsulates the behavior for a given form
function formPresenter(formId) {

    this.setFirstName = function(value) {
        $("#" + formId + "_FirstName").val(value);
    }

    this.setLastName = function(value) {
        $("#" + formId + "_LastName").val(value);
    }

    // create other functions to handle more complicated logic

    // clear fields
    this.clearInputs = function() {
        this.setFirstName("");
        this.setLastName("");
        //...
    }

    // receive Json object
    this.handleJson = function(json) {
        this.clearInputs();

        // populate fields with json object
        this.setFirstName(json.FirstName);
        this.setLastName(json.LastName);
        //...
    }

    // "constructor" logic
}

function prepareForm(formId) {
    // create a new formPresenter object and shove it onto the specified element as the "presenter"
    document.getElementById(formId).presenter = new formPresenter(formId);
}

Теперь почти вся ваша настоящая логика находится в собственном файле .js, который должен быть намного проще в обслуживании. Если вам нужен доступ к объекту formPresenter для данной формы, вам просто нужно получить ссылку на любой элемент, на который ссылается параметр formId, и получить доступ к переменной Presenter:

"document.getElementById(" + form.ClientID + ").presenter.handleJson(json);"

Примечание. Поскольку я использую JQuery, я обнаружил, что меньше необходимости даже включать любой javascript, сгенерированный сервером. Обычно я могу найти нужные мне элементы, выбрав определенное имя класса CSS (или что-то в этом роде) и выполнив все необходимые настройки / инициализации.

1 голос
/ 13 апреля 2010

Мы также проводим много JS-генераций в нашем проекте, и мы используем StringBuilder для этого.

StringBuilder sb = new StringBuilder();

sb.Append("some javascript stuff")
  .Append("some more")
  .AppendFormat("formatted stuff {0}", "here");

return sb.ToString();

Это не красиво, но никакого решения не будет.

А что касается тестирования, мы фактически не проводим никаких модульных тестов сгенерированного кода. Перед выпуском люди идут и тестируют все функции, чтобы убедиться, что они работают как положено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...