文章结构
前言:不会用Jmeter的测试工程师不是一个好的程序员。自己码的api,交给前端开发的时候,你心里有点谱吗? JMeter是神马啊? Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件。相比Loadrunner而言,JMeter小巧轻便且免费,逐渐成为了主流的性能测试工具,是每个测试人员都必须要掌握的工具之一。
Jmeter载入结果
先上结果,快速生成的Jmeter测试例程其实是没有正确的数据的,只是随机生成的数据,但是结构是正确的。因此,你需要调整下使用的测试数据以及测试的顺序,然后就可以happy的玩了,玩完记得保存,下次如果有api的变动,仍然可以继续验证改变的影响,前端的问题也可以快速的反馈了。
生成Jmeter测试计划
打开一个Jmeter测试计划,发现就是xml,如下所示。
xmlwriter来支持写xml
/// <summary>
/// Writes <'elementName' name='name' elementType='elementType'>
/// </summary>
internal static void WriteStartElement(XmlWriter xmlWriter, string elementName, string name, string elementType)
{
xmlWriter.WriteStartElement(elementName);
xmlWriter.WriteAttributeString("name", name);
xmlWriter.WriteAttributeString("elementType", elementType);
}
/// <summary>
/// Writes <'elementName' name='name'>
/// </summary>
internal static void WriteStartElement(XmlWriter xmlWriter, string elementName, string name)
{
xmlWriter.WriteStartElement(elementName);
xmlWriter.WriteAttributeString("name", name);
}
/// <summary>
/// Writes <'elementName' name='name'></'elementName'>
/// </summary>
internal static void WriteStartAndEndElement(XmlWriter xmlWriter, string elementName, string name)
{
xmlWriter.WriteStartElement(elementName);
xmlWriter.WriteAttributeString("name", name);
xmlWriter.WriteEndElement();
}
/// <summary>
/// Writes <'elementName'>'value'</'elementName'>
/// </summary>
internal static void WriteSimpleElement(XmlWriter xmlWriter, string elementName, string elementValue)
{
xmlWriter.WriteStartElement(elementName);
xmlWriter.WriteString(elementValue);
xmlWriter.WriteEndElement();
}
/// <summary>
/// Writes <'elementName' name='valueOfPropName'>'elementValue'</'elementName'>
/// </summary>
internal static void WriteElementWithTextChildren(XmlWriter xmlWriter, string elementName, string valueOfPropName,
string elementValue)
{
xmlWriter.WriteStartElement(elementName);
xmlWriter.WriteAttributeString("name", valueOfPropName);
xmlWriter.WriteString(elementValue);
xmlWriter.WriteEndElement();
}
从Controller提取api
当然自己不全写了,采用 ObjectGenerator来改。这个类应该是微软官方或者swagger的,直接拿来修改用即可。
辅助类如下:
public class ApiHelper
{
public static List<TestApi> GetAllControllers(string assembly)
{
List<TestApi> apis = new List<TestApi>();
var asm = Assembly.Load(assembly);
var ctls = asm.GetTypes().Where(x => x.BaseType == typeof(Controller) || x.IsSubclassOf(typeof(Controller)));
var list = ctls.ToList();
foreach (var ctl in ctls)
{
var methods = GetAllMetods(ctl);
var r = GetRoute(ctl);
foreach (var m in methods)
{
var api = new TestApi();
var isPost = IsPost(m);
var desc = GetDesc(m);
api.Title = desc;
api.post = isPost;
if (string.IsNullOrEmpty(desc)) continue;
var route = GetRoute(m);
if (string.IsNullOrEmpty(r))
{
api.uri = $"api/{ctl.Name.Replace("Controller", "")}/{m.Name}";
}
else
{
if (string.IsNullOrEmpty(route))
{
api.uri = r.Replace("[controller]", ctl.Name.Replace("Controller", "")).Replace("[action]", m.Name);
}
else
{
if (r.Contains("[action]"))
api.uri = r.Replace("[controller]", ctl.Name.Replace("Controller", "")).Replace("[action]", route);
else
api.uri = r.Replace("[controller]", ctl.Name.Replace("Controller", "")) + $"/{route}";
}
}
var pas = m.GetParameters();
if (isPost)
{
ObjectGenerator og = new ObjectGenerator();
var obj = og.GenerateObject(pas.FirstOrDefault()?.ParameterType ?? typeof(object));
//var json = JsonConvert.SerializeObject(obj, new JsonSerializerSettings
//{
// Formatting = Formatting.Indented,
//});
api.inParam = obj;
}
else
{
foreach (var p in pas)
{
if (string.IsNullOrEmpty(api.inParam))
api.inParam = $"{p.Name}=";
else
api.inParam += $"&{p.Name}=";
}
}
apis.Add(api);
}
}
return apis;
}
public static List<MethodInfo> GetAllMetods(Type type)
{
return type.GetMethods(BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.DeclaredOnly |
BindingFlags.Instance).ToList();
}
public static bool IsPost(MethodInfo m)
{
var cas = m.GetCustomAttributes(false);
var post = (HttpPostAttribute)(cas.ToList().FirstOrDefault(x => x.GetType() == typeof(HttpPostAttribute)));
return post != null;
}
public static string GetRoute(MethodInfo m)
{
var cas = m.GetCustomAttributes(true);
var route = (RouteAttribute)(cas.ToList().FirstOrDefault(x => x.GetType() == typeof(RouteAttribute)));
return route?.Template;
}
public static string GetDesc(MethodInfo m)
{
var cas = m.GetCustomAttributes(true);
var route = (DisplayAttribute)(cas.ToList().FirstOrDefault(x => x.GetType() == typeof(DisplayAttribute)));
return route?.Name;
}
public static string GetRoute(Type m)
{
var cas = m.GetCustomAttributes(true);
var route = (RouteAttribute)(cas.ToList().FirstOrDefault(x => x.GetType() == typeof(RouteAttribute)));
return route?.Template;
}
}
public class TestApi
{
/// <summary>
/// 相对路径
/// </summary>
public string uri { get; set; }
public string Title { get; set; }
public bool post { get; set; }
public dynamic inParam { get; set; }
public string test { get; set; }
public bool testResult { get; set; }
public string rtnError { get; set; }
}
生成jmeter
var apis = ApiHelper.GetAllControllers("SCM.AMS.AmsWxApp.APIs");
var jmeter = new JMeterGenerator();
var dir = Assembly.GetExecutingAssembly().Location;
FileInfo fi = new FileInfo(dir);
jmeter.Save(apis, fi.DirectoryName, "abc");
源码可联系作者
源码可以联系我!
这个可以按需自己写,因为并没有很好的抽象出一个工具,因此就不献丑了。