简体   繁体   English

使用单元测试测试线程安全

[英]Test thread-safe with unit tests

I'm developing my own simple IoC library which one i'd like to make thread-safe. 我正在开发自己的简单IoC库,我想使它成为线程安全的。

My typical unit test looks like this: 我的典型单元测试如下所示:

[TestMethod]
public void TestContainerUseExistingObjectFromLifetimeManagerWithFactoryMethod()
{
    // Arrange
    var container = new FsContainer();

    container
        .For<IRepository>()
        .Use(ctx => new Repository("sql_connection_string"), new ContainerControlledLifetimeManager());

    // Act
    var first = container.Resolve<IRepository>();
    var second = container.Resolve<IRepository>();

    // Arrange
    Assert.AreEqual(first.ConnectionString, "sql_connection_string");
    Assert.AreEqual(second.ConnectionString, "sql_connection_string");
    Assert.AreSame(first, second);
}

This works great before i tried to test it next manner: 在尝试以另一种方式进行测试之前,此方法效果很好:

[TestMethod]
public async Task TestMultiThreadContainerUseExistingObjectFromLifetimeManagerWithFactoryMethodAsync()
{
    // Arrange
    var container = new FsContainer();

    container
        .For<IRepository>()
        .Use(ctx => new Repository("sql_connection_string"), new ContainerControlledLifetimeManager());

    // Act
    var instances = await Task.WhenAll(
        Task.Run(() => container.Resolve<IRepository>()), 
        Task.Run(() => container.Resolve<IRepository>())
    );

    var first = instances[0];
    var second = instances[1];

    // Arrange
    Assert.AreEqual(first.ConnectionString, "sql_connection_string");
    Assert.AreEqual(second.ConnectionString, "sql_connection_string");
    Assert.AreSame(first, second);
}

This test show me, that i had issue with Assert.AreSame (my first & second instances were not same). 该测试向我展示了我对Assert.AreSame问题(我的第一个和第二个实例不相同)。

I've implemented lock statement at Resolve method and everything started to work fine. 我已经在Resolve方法上实现了lock语句,一切开始正常工作。

Question: Is it the correct way to duplicate most of the functionality in single and multi-thread way to test thread-safity? 问:是不是复制的大部分功能以正确的方式singlemulti-thread的方式来测试线程safity? Does it make sense? 是否有意义?

Testing for thread safety is hard if not impossible in most cases. 在大多数情况下,即使不是不可能,也很难进行线程安全性测试。

Your second test case can expose some issues but does not guarantee that code behaves correctly. 您的第二个测试用例可能会暴露一些问题,但不能保证代码行为正确。 Ie it could detect the code violated design by creating per-thread instance instead of one global instance if code does it consistently, but have very low chance to catch parallel access to shared dictionary (or whatever collection the code stores singletons in). 也就是说,如果代码始终如一,它可以通过创建每个线程实例而不是一个全局实例来检测违反代码的设计,但是捕获并行访问共享字典(或代码存储单例的任何集合)的机会很小。 You got lucky to actually detect a problem with the test - possibly code that ensures instance of singleton is slow enough to let two threads start and hit the problem. 您很幸运能真正检测到测试中的问题-可能的代码可确保单例实例足够慢,以使两个线程启动并解决问题。 Test would unlikely to catch errors if code would be fast and somewhat correct (ie using double-checked locking without locking). 如果代码是快速且正确的(例如,使用双重检查锁定而不锁定),则测试不太可能捕获错误。

For writing thread-safe code you should start with known to be correct conservative code (ie just lock around all operations) and than make small changes where you can prove correctness by code review (and have tests that help validate functionality). 为了编写线程安全代码,您应该从已知的正确保守代码开始(即仅锁定所有操作),然后进行一些小的更改,在这些地方可以通过代码检查证明正确性(并进行有助于验证功能的测试)。

If you concerned about particular piece of code sometimes you can intentionally slow down the code (ie Sleep(1000) in constructor/callback) to force particular timings of the code. 如果您担心特定的代码段,有时可以故意降低代码速度Sleep(1000) ,构造函数/回调中的Sleep(1000) ),以强制执行特定的代码计时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM