- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个随机失败的单元测试,我无法解释。这涉及使用 Rx.NET 的可观察序列和我为转换序列而制作的扩展方法。首先,让我展示一下测试是如何失败的:
Machine.Specifications.SpecificationException: Expected: System.Collections.Generic.List`1[System.Int32]:{ [8], [10], [11]} But was: System.Collections.Generic.List`1[System.Int32]:{ [8], [10], [11], [8], [10], [11]}
OK, so you see, I get the entire sequence twice instead of once. Here's the test:
[Subject(typeof(ObservableExtensions), "Shutter Current Readings")]
internal class when_a_shutter_current_reading_is_received
{
Establish context = () => source = "Z8\nZ10\nZ11\n".ToObservable();
Because of = () => source
.ShutterCurrentReadings().Trace("Unbelievable")
.SubscribeAndWaitForCompletion(item => elementHistory.Add(item));
It should_receive_the_current_readings = () => elementHistory.ShouldEqual(expectedElements);
static List<int> elementHistory = new List<int>();
static List<int> expectedElements = new List<int> {8, 10, 11};
static IObservable<char> source;
}
SubscribeAndWaitForCompletion()
是一个扩展方法,定义如下:
public static void SubscribeAndWaitForCompletion<T>(this IObservable<T> sequence, Action<T> observer)
{
var sequenceComplete = new ManualResetEvent(false);
var subscription = sequence.Subscribe(
onNext: observer,
onCompleted: () => sequenceComplete.Set()
);
sequenceComplete.WaitOne();
subscription.Dispose();
sequenceComplete.Dispose();
}
你会注意到那里有一个 .Trace()
调用,另一个在扩展方法中,这会通过 NLog 生成关于可观察序列的日志记录,这是跟踪输出:
20:43:43.1547|DEBUG|c__DisplayClass0_1`1|Unbelievable[1]: Subscribe()20:43:43.1547|DEBUG|c__DisplayClass0_1`1|ShutterCurrent[1]: Subscribe()20:43:43.1547|DEBUG|c__DisplayClass0_1`1|ShutterCurrent[1]: OnNext(8)20:43:43.1547|DEBUG|c__DisplayClass0_1`1|Unbelievable[1]: OnNext(8)20:43:43.1547|DEBUG|c__DisplayClass0_1`1|ShutterCurrent[1]: OnNext(10)20:43:43.1547|DEBUG|c__DisplayClass0_1`1|Unbelievable[1]: OnNext(10)20:43:43.1547|DEBUG|c__DisplayClass0_1`1|ShutterCurrent[1]: OnNext(11)20:43:43.1547|DEBUG|c__DisplayClass0_1`1|Unbelievable[1]: OnNext(11)20:43:43.1547|DEBUG|c__DisplayClass0_1`1|ShutterCurrent[1]: OnCompleted()20:43:43.1547|DEBUG|c__DisplayClass0_1`1|Unbelievable[1]: OnCompleted()20:43:43.1547|DEBUG|c__DisplayClass0_1`1|Unbelievable[1]: Dispose()20:43:43.1547|DEBUG|c__DisplayClass0_1`1|ShutterCurrent[1]: Dispose()Child test failed
This is pretty much what I would expect. I get one trace output from inside my extension method, then another on the transformed sequence outside the extension method. Each element in the sequence flows through the system exactly once, just as expected. And yet, I get the entire sequence captured twice in my test.
I had better provide the extension method so we can see what it does. Here it is:
public static IObservable<int> ShutterCurrentReadings(this IObservable<char> source)
{
const string shutterCurrentPattern = @"^Z(?<Current>\d{1,2})[^0-9]";
var shutterCurrentRegex =
new Regex(shutterCurrentPattern, RegexOptions.Compiled | RegexOptions.ExplicitCapture);
var buffers = source.Publish(s => s.BufferByPredicates(p => p == 'Z', q => !char.IsDigit(q)));
var shutterCurrentValues = from buffer in buffers
let message = new string(buffer.ToArray())
let patternMatch = shutterCurrentRegex.Match(message)
where patternMatch.Success
let shutterCurrent = int.Parse(patternMatch.Groups["Current"].Value)
select shutterCurrent;
return shutterCurrentValues.Trace("ShutterCurrent");
}
因此这里的目的是从数据流中挑选出电流传感器的读数。读数采用 Znn 格式(字面量“Z”后跟一个或两个十进制数字后跟一个换行符。扩展方法将原始输入字符序列转换为表示当前读数的整数序列。过滤器使用 Rx Buffer
运算符缓冲它认为可能是有效传感器读数的字符。缓冲区在看到“Z”字符时打开,在看到非数字字符时关闭。这是通过匹配和解析进行双重检查在正则表达式中,然后如果结果全部通过,则将其转换为整数并在输出序列中发出。
谁能看出为什么我的结果中可能会出现双重数据?
更新:与调查相关的附加代码。
public static IObservable<IList<char>> BufferByPredicates(this IObservable<char> source,
Predicate<char> bufferOpening, Predicate<char> bufferClosing)
{
return source.Buffer(source.Where(c => bufferOpening(c)), x => source.Where(c => bufferClosing(c)));
}
Trace
扩展方法可在 NuGet 包 TA.ASCOM.ReactiveCommunications
(我的一个)中找到,但这是来源:
public static IObservable<TSource> Trace<TSource>(this IObservable<TSource> source, string name)
{
var log = LogManager.GetLogger(name);
var id = 0;
return Observable.Create<TSource>(observer =>
{
var idClosure = ++id;
Action<string, object> trace = (m, v) => log.Debug("{0}[{1}]: {2}({3})", name, idClosure, m, v);
trace("Subscribe", "");
var disposable = source.Subscribe(
v =>
{
trace("OnNext", v);
observer.OnNext(v);
},
e =>
{
trace("OnError", "");
observer.OnError(e);
},
() =>
{
trace("OnCompleted", "");
observer.OnCompleted();
});
return () =>
{
trace("Dispose", "");
disposable.Dispose();
};
});
}
我怀疑我可能从其他人那里复制了这段代码,但我似乎没有记下是谁。
最佳答案
编辑:
这是一种在 LinqPad 中模拟问题的方法,无需使用 MSpec/NChrunch (?) runner:
void Main()
{
//static initializers
List<int> expectedElements = new List<int> { 8, 10, 11 };
List<int> elementHistory = new List<int>();
IObservable<char> source;
//simulated continuous running of MSpec test
for (int i = 0; i < 20; i++)
{
//establish
source = "Z8\nZ10\nZ11\n".ToObservable();
//because
source
.ShutterCurrentReadings()
.Trace("Unbelievable")
.SubscribeAndWaitForCompletion(item => elementHistory.Add(item));
//it
elementHistory.Dump(i.ToString()); //Linqpad
if(elementHistory.Count > 3)
throw new Exception("Assert.ShouldNotHappen");
}
}
public static class Extensions
{
public static IObservable<int> ShutterCurrentReadings(this IObservable<char> source)
{
const string shutterCurrentPattern = @"^Z(?<Current>\d{1,2})[^0-9]";
var shutterCurrentRegex =
new Regex(shutterCurrentPattern, RegexOptions.Compiled | RegexOptions.ExplicitCapture);
var buffers = source.Publish(s => s.BufferByPredicates(p => p == 'Z', q => !char.IsDigit(q)));
var shutterCurrentValues = from buffer in buffers
let message = new string(buffer.ToArray())
let patternMatch = shutterCurrentRegex.Match(message)
where patternMatch.Success
let shutterCurrent = int.Parse(patternMatch.Groups["Current"].Value)
select shutterCurrent;
return shutterCurrentValues.Trace("ShutterCurrent");
}
public static void SubscribeAndWaitForCompletion<T>(this IObservable<T> sequence, Action<T> observer)
{
var sequenceComplete = new ManualResetEvent(false);
var subscription = sequence.Subscribe(
onNext: observer,
onCompleted: () => sequenceComplete.Set()
);
sequenceComplete.WaitOne();
subscription.Dispose();
sequenceComplete.Dispose();
}
public static IObservable<TSource> Trace<TSource>(this IObservable<TSource> source, string name)
{
var log = LogManager.GetLogger(name);
var id = 0;
return Observable.Create<TSource>(observer =>
{
var idClosure = ++id;
Action<string, object> trace = (m, v) => log.Debug("{0}[{1}]: {2}({3})", name, idClosure, m, v);
trace("Subscribe", "");
var disposable = source.Subscribe(
v =>
{
trace("OnNext", v);
observer.OnNext(v);
},
e =>
{
trace("OnError", "");
observer.OnError(e);
},
() =>
{
trace("OnCompleted", "");
observer.OnCompleted();
});
return () =>
{
trace("Dispose", "");
disposable.Dispose();
};
});
}
public static IObservable<IList<char>> BufferByPredicates(this IObservable<char> source,
Predicate<char> bufferOpening, Predicate<char> bufferClosing)
{
return source.Buffer(source.Where(c => bufferOpening(c)), x => source.Where(c => bufferClosing(c)));
}
}
这失败了,就像你的场景一样。
我最好的修复建议是将 elementHistory
的初始化移动到 Establish
步骤。您还可以将 source
变量从 establish 移开,这样您的测试将如下所示:
internal class when_a_shutter_current_reading_is_received
{
Establish context = () => elementHistory = new List<int>();
Because of = () => "Z8\nZ10\nZ11\n".ToObservable()
.ShutterCurrentReadings()
.Trace("Unbelievable")
.SubscribeAndWaitForCompletion(item => elementHistory.Add(item));
It should_receive_the_current_readings = () => elementHistory.ShouldEqual(expectedElements);
static List<int> elementHistory;
static List<int> expectedElements = new List<int> { 8, 10, 11 };
}
您可能还想查看 Microsoft.Reactive.Testing
,它为 Rx 查询提供了一些更强大的测试,尽管它不会像您的测试那样简单。
旧答案:
由于缺少 Trace
、ShouldEqual
和 BufferByPredicates
函数,我无法编译您的代码。如果它们来自外部来源,请记录来源。
我猜测问题源于 BufferByPredicates
实现、Trace
实现、Publish 后缺少
,或静态 Connect
elementHistory
。
我最好的猜测是静态 elementHistory
:如果该测试同时运行两次,您就会遇到竞争条件,并且您最终可能会得到双重结果(Establish
运行两次,然后因为
运行两次,然后它
会失败。
关于c# - 为什么我的 Rx.NET observable 似乎生成了整个序列两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49416593/
创建使用.NET框架的asp.net页面时,访问该页面的客户端是否需要在其计算机上安装.NET框架? IE。用户访问www.fakesite.com/default.aspx,如果他们没有安装框架,他
我阅读了很多不同的博客和 StackOverflow 问题,试图找到我的问题的答案,但最后我找不到任何东西,所以我想自己问这个问题。 我正在构建一个应用程序,其中有一个长时间运行的工作线程,它执行一些
已锁定。这个问题及其答案是locked因为这个问题是题外话,但却具有历史意义。目前不接受新的答案或互动。 我一直想知道为什么微软为这样一个伟大的平台选择了一个如此奇怪的、对搜索引擎不友好的名称。他们就
.Net Framework .Net .NET Standard的区别 1、.NET Framework 在未来.NET Framework或许成为过去时,目前还是有很多地方在使用的。这一套
如果有选择的话,您会走哪条路? ASP.NET Webforms + ASP.NET AJAX 或 ASP.NET MVC + JavaScript Framework of your Choice
我有一个 Web 服务,它通过专用连接通过 https 使用第三方 Web 服务,我应用了 ServicePointManager.ServerCertificateValidationCallbac
为什么我应该选择ASP.NET Web Application (.NET Framework)而不是ASP.NET Core Web Application (.NET Framework)? 我在
我在网络上没有找到任何关于包含 .NET Standard、.NET Core 和 .NET Framework 项目的 .NET 解决方案的公认命名约定。 就我而言,我们在 .NET 框架项目中有以
.NET Compact 是 .NET 的完美子集吗? 假设我考虑了屏幕大小和其他限制并避免了 .NET Compact 不支持的类和方法,或者 .NET Compact 是一个不同且不兼容的 GUI
我已经阅读了所有我能找到的关于 connectionManagement 中的 maxconnection 设置的文章:即 http://support.microsoft.com/kb/821268
我现在正在使用asp.net mvc,想知道使用内置的Json或 Json.Net哪个是更好的选择,但我不确定一个人是否比另一个人有优势。 另外,如果我确实选择沿用Json.Net的路线,那么我应该选
在 Visual Studio 中,您至少可以创建三种不同类型的类库: 类库(.NET Framework) 类库(.NET 标准) 类库(.NET Core) 虽然第一个是我们多年来一直使用的,但我
.NET 和 ASP.NET 之间有什么区别?它们有什么关系? 最佳答案 ASP.Net 基于 .Net 框架构建,提供有关 Web 开发的附加功能。 你可以去看看wikipedia article
在安装更高版本(3.0)之前,我需要安装.net框架1.1和2.0吗?或者单独安装 3.0 框架就足够了,并为在早期框架版本上编写的软件提供支持?谢谢 ,丽然 最佳答案 不,您不必安装以前的框架。 我
我正在开发一个项目,人们可以“更新”类别,例如更改类别的名称。我收到以下消息 This is called after clicking update 按钮 with the SQL statemen
.NET 类 System.Net.CookieContainer 线程安全吗? --更新:交 key 答复-- 是否有任何方法可以确保异步请求期间修改的变量(即 HttpWebRequest.Coo
我正在使用 JScript.NET 在我编写的 C# WinForms 应用程序中编写脚本。它工作得很好,但我只是尝试在脚本中放置一些异常处理,但我无法弄清楚如何判断我的 C# 代码抛出了哪种类型的异
我需要你的帮助, 比如我有一个小数类型的变量,我想这样取整。 例如 3.0 = 3 3.1 = 4 3.2 = 4 3.3 = 4 3.4 = 4 3.5 = 4 3.6 = 4 3.7 = 4 3.
我使用过这样的代码:http://msdn.microsoft.com/en-us/library/dw70f090.aspx在 ASP.NET 中工作之前访问数据库(2-3 年前)。我没有意识到我正
自 ConfigurationManager .NET Standard 中不存在,检索正在执行的程序集的应用程序设置的最佳方法是什么,无论是 web.config或 appSettings.{env
我是一名优秀的程序员,十分优秀!