用C#在Visual Studio写Javascript单元测试(Firefox内核)
引用nuget包:
注意:Geckofx45 nuget包必须是最后引用,否则初始化会出错
编写JsRunner
using Gecko;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Way.UnitTest
{
class JsRunner:IDisposable
{
static JsRunner()
{
Xpcom.Initialize("Firefox");
} static List<JsFileReference> ReferenceConfigs = new List<JsFileReference>();
static List<string> GlobalJSFiles = new List<string>();
/// <summary>
/// 设置js文件依赖
/// </summary>
/// <param name="jsFile">js文件路径</param>
/// <param name="references">所依赖的js文件路径</param>
public static void SetJsReference(string jsFile,IEnumerable<string> references)
{
ReferenceConfigs.Add(new JsFileReference() {
JsFile = jsFile,
References = references,
});
}
/// <summary>
/// 添加全局js文件
/// </summary>
/// <param name="jsFile"></param>
public static void AddGlobalJsFile(string jsFile)
{
GlobalJSFiles.Add(jsFile);
} public JsRunner()
{
JsFiles.AddRange(GlobalJSFiles);
}
~JsRunner()
{
Dispose();
}
List<string> JsFiles = new List<string>();
/// <summary>
/// 添加js文件
/// </summary>
/// <param name="jsPath">js文件路径</param>
public void AddJsFile(string jsPath)
{
putJsFileContentToList(jsPath); } void putJsFileContentToList(string jsPath)
{
if (JsFiles.Contains(jsPath) )
{
return;
}
//查找该js是否引用其他js
var arr = ReferenceConfigs.Where(m => string.Equals(m.JsFile, jsPath, StringComparison.CurrentCultureIgnoreCase));
foreach( var item in arr )
{
foreach( var path in item.References )
{
putJsFileContentToList(path);
}
}
JsFiles.Add(jsPath);
} /// <summary>
/// 运行js代码
/// </summary>
/// <typeparam name="T">返回值类型</typeparam>
/// <param name="jsCode">一段js代码。如:return data.name;</param>
/// <param name="data">传到js里面的对象,js可以通过data.*直接使用此参数</param>
/// <returns></returns>
public T Run<T>(string jsCode, object data)
{
var gecko = new GeckoWebBrowser();
gecko.CreateControl();bool loadFinished = false; gecko.NavigationError += (s, e) =>
{
};
gecko.NSSError += (s, e) =>
{
};
gecko.DocumentCompleted += (s, e) => {
loadFinished = true;
};
string tempFileName = System.IO.Path.GetTempFileName();
System.IO.StreamWriter sw = new StreamWriter(System.IO.File.OpenWrite(tempFileName)); sw.WriteLine("<!DOCTYPE html>");
sw.WriteLine("<html>");
foreach (var path in JsFiles)
{
sw.WriteLine("<script src=\"file:///" + path + "\" type=\"text/javascript\"></script>");
}
sw.WriteLine("<body>"); sw.WriteLine("<input type=hidden id='inputResult'>");
sw.WriteLine("<input type=hidden id='inputError'>");
sw.WriteLine("</body>");
sw.WriteLine("</html>");
sw.Dispose(); gecko.Navigate("file:///" + tempFileName); while (!loadFinished)
{
System.Threading.Thread.Sleep();
System.Windows.Forms.Application.DoEvents();
}
System.IO.File.Delete(tempFileName); var jsContext = new AutoJSContext(gecko.Window); var js = @"
(function(d){
try{
var result = (function(data){" + jsCode + @"})(d);
return JSON.stringify(result);
}catch(e)
{
if(typeof e == 'string')
return JSON.stringify({ ______err : e , line:0 });
else
return JSON.stringify({ ______err : e.message , line:e.lineNumber });
}
})(" + (data == null ? "null" : Newtonsoft.Json.JsonConvert.SerializeObject(data)) + @");
"; string result;
jsContext.EvaluateScript(js, out result);
jsContext.Dispose();
gecko.Dispose(); if(result.StartsWith("{\"______err\":"))
{
var errObj = Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(result);
string errMsg = errObj.Value<string>("______err");
//int lineNumber = errObj.Value<int>("line") - 3;
throw new Exception(errMsg);
}
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result);
} /// <summary>
/// 读取js文件内容
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
string readJsFile(string filePath)
{
using (System.IO.FileStream fs = System.IO.File.OpenRead(filePath))
{
var data = new byte[fs.Length];
var isUtf8 = IsUTF8(fs);
fs.Position = ;
fs.Read(data, , data.Length);
if (isUtf8)
{
return Encoding.UTF8.GetString(data);
}
else
{
return Encoding.GetEncoding("gb2312").GetString(data);
}
}
} /// <summary>
/// 判断流是否是utf-8编码
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
static bool IsUTF8(Stream stream)
{
bool IsUTF8 = true; while (stream.Position < stream.Length)
{
byte b = (byte)stream.ReadByte();
if (b < 0x80) // (10000000): 值小于0x80的为ASCII字符
{ }
else if (b < (0xC0)) // (11000000): 值介于0x80与0xC0之间的为无效UTF-8字符
{
IsUTF8 = false;
break;
}
else if (b < (0xE0)) // (11100000): 此范围内为2字节UTF-8字符
{
if (stream.Position >= stream.Length - )
{
break;
}
byte nextByte = (byte)stream.ReadByte();
if ((nextByte & (0xC0)) != 0x80)
{
IsUTF8 = false;
break;
}
}
else if (b < (0xF0)) // (11110000): 此范围内为3字节UTF-8字符
{
if (stream.Position >= stream.Length - )
{
break;
} byte nextByte1 = (byte)stream.ReadByte();
byte nextByte2 = (byte)stream.ReadByte();
if ((nextByte1 & (0xC0)) != 0x80 || (nextByte2 & (0xC0)) != 0x80)
{
IsUTF8 = false;
break;
}
}
else
{
IsUTF8 = false;
break;
}
} return IsUTF8; } public void Dispose()
{
JsFiles.Clear();
}
} class JsFileReference
{
/// <summary>
/// js文件
/// </summary>
public string JsFile;
/// <summary>
/// 所依赖的js文件
/// </summary>
public IEnumerable<string> References; } }
编写单元测试基类
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Gecko; namespace Way.UnitTest.Javascript
{
/// <summary>
/// 其他js单元测试,建议继承此类
/// </summary>
[TestClass]
public class JSUnitTest
{ static JSUnitTest()
{
Xpcom.Initialize("Firefox"); //组合文件夹路径
var solutionPath = AppDomain.CurrentDomain.BaseDirectory + "\\..\\..\\..\\"; //添加全局使用的js文件
JsRunner.AddGlobalJsFile($"{solutionPath}\\js\\xpos-10.core.js"); //定义js文件的依赖关系,这里只是举例,文件实际不存在
//设置kkk.js依赖于a1.js a2.js 两个文件,
//这样,每当使用kkk.js文件,系统会自动引入a1.js a2.js 两个文件
JsRunner.SetJsReference($"{solutionPath}\\kkk.js", new string[] {
//这里写上所依赖js文件的路径
$"{solutionPath}\\a1.js",
$"{solutionPath}\\a2.js"
}); } }
}
编写测试代码
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Way.UnitTest.Javascript
{
[TestClass]
public class Example : JSUnitTest
{ [TestMethod]
public void Test()
{
using (JsRunner jsEngine = new JsRunner())
{
//编写js代码
var js = @"
return data.name;
";
//运行js代码
var result = jsEngine.Run<string>(js, new {name="JACK"});
if (result != "JACK")
throw new Exception("运算结果错误");
}
} }
}
用C#在Visual Studio写Javascript单元测试(Firefox内核)的更多相关文章
- 用C#在Visual Studio写Javascript单元测试
1.在vs创建一个标准的单元测试工程 2.引用nuget包:Edge.js 我是用的是6.11.2版本 3.编写JsRunner类 using EdgeJs; using System; using ...
- Visual Studio 中的单元测试 UNIT TEST
原文:Visual Studio 中的单元测试 UNIT TEST 注:本文系作者原创,可随意转载,但请注明出处.如实在不愿注明可留空,强烈反对更改原创出处.TDD(Test-Driven Devel ...
- 基于Visual Studio .NET2015的单元测试
基于Visual Studio .NET2015的单元测试 1. 在Visual Studio .NET2015中创建任意项目. 2. 在某个公共类的公共方法的名称上面点击右键,选择“创建 ...
- 基于Visual Studio .NET2015的单元测试 OpenCover
https://www.cnblogs.com/XiaoRuLiang/p/10095723.html 基于Visual Studio .NET2015的单元测试 1. 在Visual Stud ...
- Visual Studio中UnitTesting单元测试模板代码生成
在软件研发过程中,单元测试的重要性直接影响软件质量.经验表明一个尽责的单元测试方法将会在软件开发的某个阶段发现很多的Bug,并且修改它们的成本也很低.在软件开发的后期阶段,Bug的发 ...
- Visual Studio 2013进行单元测试
使用Visual Studio 2013进行单元测试--初级篇 1.打开VS2013 --> 新建一个项目.这里我们默认创建一个控制台项目.取名为UnitTestDemo 2.在解决方案里面 ...
- 使用Visual Studio 2013进行单元测试
使用Visual Studio 2013进行单元测试 1.打开VS2013 --> 新建一个项目.这里我们默认创建一个控制台项目.取名为UnitTestDemo 2.在解决方案里面新增一个单元测 ...
- Visual Studio(VS)C++单元测试
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Visual Studio(VS)C++单元测试 本文地址:http://techie ...
- 1,[VS入门教程] 使用Visual Studio写c语言 入门与技巧精品文~~~~下载安装篇
Microsoft Visual Studio是微软(俗称巨硬)公司出品的强大IDE(Integrated Development Environment 集成开发环境),功能强大齐全,界面舒服之类的 ...
随机推荐
- PayPal加密证书.pem的生成
How do I create a public certificate for use with PayPal Encrypted Website Payments? Before you ca ...
- 在Ubuntu平台上创建Cordova Camera HTML5应用
在这篇文章中,我们将具体介绍怎样使用Cordova Camera HTML5 应用.很多其它关于Cordova的开发指南,开发人员能够參考文章"the Cordova Guide" ...
- bootstrap-table方法之:expandRow-collapseRow,展开或关闭当前行数据
官方演示地址:http://issues.wenzhixin.net.cn/bootstrap-table/methods/expandRow-collapseRow.html <!DOCTYP ...
- .net core2.0添加json文件并转化成类注入控制器使用 让js调试更简单—console
.net core2.0添加json文件并转化成类注入控制器使用 上一篇,我们介绍了如何读取自定义的json文件,数据是读取出来了,只是处理的时候太麻烦,需要一遍一遍写,很枯燥.那么有没有很好的办法呢 ...
- addSubview和insertSubview 区别
子视图是以栈的方式存放的. 每次addsubview时都是在最后面添加. 每次在addsubview前和addsubview后可以看看[self.view.subViews count]: 你看看你 ...
- checkbox是否选中判断
三种方式: $('#checkAll').bind('click',function(){ //第一种 console.log(this.checked); //第二种 console.log($(t ...
- 【Codevs1322】单词矩阵
Position: http://codevs.cn/problem/1322/ List Codevs1322 单词矩阵 List Description Input Output Sample I ...
- 2-sat总结
算法 构造一个有向图G,每个变量xi拆成两个点2i和2i+1 分别表示xi为假,xi为真 那么对于“xi为真或xj为假”这样的条件 我们就需要连接两条边 2*i —>2*j(表示如果i为假,那么 ...
- 使用centos 5.x 64位系统安装astgo 2014 v7.3教程(含全套安装文件)
版本特色: 全自动安装 安装过程中不用频繁输入yes或回车 自带完整号码归属地数据库 自带触屏版WAP ·首先确定你需要使用astgo 2014 7.0还是7.3: astgo 2014 v 7.0 ...
- Ubuntu下FileZilla的安装(转载)
转自:http://os.51cto.com/art/201103/247564.htm FileZilla是一个免费而且开源的FTP客户端软件,共有两种版本:客户端版本.服务器版本.FileZill ...