Здесь я приведу пример тестового блока с вспомогательной функцией.
Контрольный пример: - вспомогательная функция Request_With_Query: - HttpReuqestSetup (путем mokcing HttprequestObject)
Я заметил, что издевался над объектом регистратора, так как он может помочь мне с предоставлением полезной информации
функция выглядит как
public static class HttpTrigger
{
[FunctionName("HttpTrigger")]
public async static Task<IActionResult> RunAsync([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequest req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = new StreamReader(req.Body).ReadToEnd();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
}
и вот так выглядит мой тестовый класс:
[TestClass]
public class HttpTriggerTest : FunctionTestHelper.FunctionTest
{
[TestMethod]
public async Task Request_With_Query()
{
var query = new Dictionary<String, StringValues>();
query.TryAdd("name", "ushio");
var body = "";
var result = await HttpTrigger.RunAsync(req: HttpRequestSetup(query, body), log: log);
var resultObject = (OkObjectResult)result;
Assert.AreEqual("Hello, ushio", resultObject.Value);
}
[TestMethod]
public async Task Request_Without_Query()
{
var query = new Dictionary<String, StringValues>();
var body = "{\"name\":\"yamada\"}";
var result = await HttpTrigger.RunAsync(HttpRequestSetup(query, body), log);
var resultObject = (OkObjectResult)result;
Assert.AreEqual("Hello, yamada", resultObject.Value);
}
[TestMethod]
public async Task Request_Without_Query_And_Body()
{
var query = new Dictionary<String, StringValues>();
var body = "";
var result = await HttpTrigger.RunAsync(HttpRequestSetup(query, body), log);
var resultObject = (BadRequestObjectResult)result;
Assert.AreEqual("Please pass a name on the query string or in the request body", resultObject.Value);
}
}
Вот классы Helper
с использованием Microsoft.AspNetCore.Http; использование Microsoft.AspNetCore.Http.Internal; использование Microsoft.Azure.WebJobs; использование Microsoft.Azure.WebJobs.Host; использование Microsoft.Extensions.Primitives; используя Moq; используя Систему; using System.Collections.Generic; используя System.IO; используя System.Net.Http; используя System.Text; используя System.Threading; используя System.Threading.Tasks;
namespace FunctionTestHelper
{
public abstract class FunctionTest
{
protected TraceWriter log = new VerboseDiagnosticsTraceWriter();
public HttpRequest HttpRequestSetup(Dictionary<String, StringValues> query, string body)
{
var reqMock = new Mock<HttpRequest>();
reqMock.Setup(req => req.Query).Returns(new QueryCollection(query));
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(body);
writer.Flush();
stream.Position = 0;
reqMock.Setup(req => req.Body).Returns(stream);
return reqMock.Object;
}
}
public class AsyncCollector<T> : IAsyncCollector<T>
{
public readonly List<T> Items = new List<T>();
public Task AddAsync(T item, CancellationToken cancellationToken = default(CancellationToken))
{
Items.Add(item);
return Task.FromResult(true);
}
public Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(true);
}
}
}
public class VerboseDiagnosticsTraceWriter : TraceWriter
{
public VerboseDiagnosticsTraceWriter() : base(TraceLevel.Verbose)
{
}
public override void Trace(TraceEvent traceEvent)
{
Debug.WriteLine(traceEvent.Message);
}
}
Используйте подобный шаблон в вашем случае, вы должны быть в состоянии издеваться и писать UT мирно.
Надеюсь, это поможет.
Направляющие 2.3.x теперь позволяют Вам делать:
render @items
намного более простой..
Я запущу с одного из своего избранного. При вызове частичного с набором, вместо цикличного выполнения через набор и вызове его для каждого объекта, можно использовать это:
render :partial => 'items', :collection => @items
Это назовет частичное однажды на объект и передаст объект локальной переменной каждый раз. Вы не должны волноваться о ноле, проверяющем @items также.
integer.ordinalize - это один маленький метод, на который я недавно наткнулся.
1.ordinalize = "1st"
3.ordinalize = "3rd"
Если у вас есть модель с некоторыми методами класса и именованными областями действия:
class Animal < ActiveRecord::Base
named_scope 'nocturnal', :conditions => {'nocturnal' => true}
named_scope 'carnivorous', :conditions => {'vegetarian' => true}
def self.feed_all_with(food)
self.all.each do |animal|
animal.feed_with(food)
end
end
end
Затем вы можете вызывать методы класса через именованную область действия:
if night_time?
Animal.nocturnal.carnivorous.feed_all_with(bacon)
end
Если вы добавите маршрутизацию для ресурса:
ActionController::Routing::Routes.draw do |map|
map.resources :maps
end
и зарегистрируете дополнительные типы MIME:
Mime::Type.register 'application/vnd.google-earth.kml+xml', :kml
Вам не нужен блок response_to
в вашем контроллере для обслуживания эти дополнительные типы. Вместо этого просто создайте представления для определенных типов, например 'show.kml.builder'
или 'index.kml.erb'
. Rails будет отображать эти специфичные для типа шаблоны при получении запросов на '/ maps.kml'
или '/ maps / 1.kml'
, соответственно устанавливая тип ответа.
Вы можете воспользоваться тем, что определения классов Ruby активны и что Rails кэширует классы в производственной среде, чтобы гарантировать, что постоянные данные будут только извлекается из базы данных при запуске приложения.
Например, для модели, представляющей страны, вы должны определить константу, которая выполняет запрос Country.all
при загрузке класса:
class Country < ActiveRecord::Base
COUNTRIES = self.all
.
.
.
end
Вы можете использовать эту константу в шаблоне представления (возможно, в помощнике выбора), обратившись к Country :: COUNTRIES
. Например:
<%= select_tag(:country, options_for_select(Country::COUNTRIES)) %>
Чтобы просмотреть список установленных гемов, вы можете запустить:
gem server
Затем укажите в браузере:
http://localhost:8808
Вы получите хорошо отформатированный список ваших драгоценных камней со ссылками на rdoc, Интернет и любые другие зависимости. Намного лучше, чем:
gem list
в вашем environment.rb вы можете определить новые форматы даты / времени, например
[Time::DATE_FORMATS, Date::DATE_FORMATS].each do |obj|
obj[:dots] = "%m.%d.%y"
end
, поэтому в ваших представлениях вы можете использовать:
Created: <%= @my_object.created_at.to_s(:dots) %>
, который будет напечатан следующим образом:
Created: 06.21.09
Чтобы избежать дублирования отправки форм, в Rails есть удобная опция для тегов отправки:
submit_tag "Submit", :disable_with => "Saving..."
Это добавляет поведение кнопке отправки, чтобы отключить ее после нажатия и отобразить «Сохранение ...» вместо «Отправить».
Rails 4+
DEPRECATION WARNING: :disable_with option is deprecated and
will be removed from Rails 4.1. Use 'data: { disable_with: 'Text' }' instead.
Таким образом, приведенное выше становится:
submit_tag 'Submit', data: { disable_with: 'Text' }
ActionView::Base.default_form_builder = MyFormBuilderClass
Very useful when you're creating your own form builders. A much better alternative to manually passing :builder, either in your views or in your own custom_form_for
helper.
В настоящее время мне нравятся div_for
и content_tag_for
<% div_for(@comment) do %>
<!-- code to display your comment -->
<% end %>
Приведенный выше код отображает это:
<div id="comment_123" class="comment">
<!-- code to display your comment -->
</div>
Хотите, чтобы класс CSS был комментарий other_class
? Нет проблем:
<% div_for(@comment, :class => 'other_class') do %>
<!-- code to display your comment -->
<% end %>
Хотите диапазон, а не div? Нет проблем, content_tag_for
спешит на помощь!
<% content_tag_for(:span, @comment) do %>
<% end %>
# Becomes...
<span id="comment_123" class="comment">
<!-- code to display your comment -->
</span>
content_tag_for
также отлично подходит, если вы хотите использовать префикс id
. Использую для загрузки гифок.
<% content_tag_for(:span, @comment, 'loading') do %>
<%= image_tag 'loading.gif' -%>
<% end %>
# Becomes...
<span id="loading_comment_123" class="comment">
<img src="loading.gif" />
</span>
The returning block is a great way to return values:
def returns_a_hash(id)
returning Hash.new do |result|
result["id"] = id
end
end
Will return a hash. You can substitute any other types as well.
Вы можете изменить поведение модели для вашего набора тестов. Допустим, у вас есть определенный метод after_save, и вы не хотите, чтобы это происходило в ваших модульных тестах. Вот как это работает:
# models/person.rb
class Person < ActiveRecord::Base
def after_save
# do something useful
end
end
# test/unit/person_test.rb
require 'test_helper'
class PersonTest < ActiveSupport::TestCase
class ::Person
def after_save
# do nothing
end
end
test "something interesting" do
# ...
end
end