Visual studio 2013 如何延迟web测试的第一个请求的执行?

Visual studio 2013 如何延迟web测试的第一个请求的执行?,visual-studio-2013,load-testing,web-testing,Visual Studio 2013,Load Testing,Web Testing,在Visual Studio 2013 Web性能测试中,如何将“.webtest”中的第一个请求延迟发送一段我指定的时间?我的web测试是负载测试的一部分。web测试的第一个请求应该在数据源字段指定的延迟期之后发出。确定何时应发出请求只是: delayPeriod = dataSourceValue - ( timeNow - loadTestStartTime ) 将此delayPeriod写入请求的思考时间会导致正确的延迟。不幸的是,思考时间是在收到请求响应后应用的。因此,很容易将web

在Visual Studio 2013 Web性能测试中,如何将“.webtest”中的第一个请求延迟发送一段我指定的时间?我的web测试是负载测试的一部分。web测试的第一个请求应该在数据源字段指定的延迟期之后发出。确定何时应发出请求只是:

delayPeriod = dataSourceValue - ( timeNow - loadTestStartTime )
将此
delayPeriod
写入请求的思考时间会导致正确的延迟。不幸的是,思考时间是在收到请求响应后应用的。因此,很容易将web测试的第二个请求延迟到所需的时间。我想在第一次请求之前推迟

作为一种解决方法,我已经包含了一个对
http://localhost/
并将预期状态代码结果设置为404。所需延迟设置为此请求的思考时间。但这会向
localhost
添加一个不需要的请求

背景:
我们有一个来自web服务器的日志文件。它给出了每个请求的URL和时间。我们希望以与记录请求时相同的速率重复该日志文件中的请求。

据我所知,您对本地主机的虚拟请求的解决方案非常好。但这里有另一种方法

两部分:

(1) 将负载测试开始时间复制到web测试上下文的负载测试插件:

[DisplayName("Load Test Start Time")]
[Description("Record the load test start time in the context of new web test iterations")]
public class LoadTestStartTime : ILoadTestPlugin
{
    public const string LoadTestStartTimeContextParameterName = "$LoadTestStartTime";

    public void Initialize(LoadTest loadTest)
    {
        DateTime startTime = DateTime.Now;

        // Copy the load test start time into the context of each new test
        loadTest.TestStarting += (sender, e) =>
        {
            e.TestContextProperties[LoadTestStartTimeContextParameterName] = startTime;
        };
    }
}
(2) 一个web测试插件,它从一个属性获取延迟时间,该属性可以是静态值或上下文参数,可以是HH:MM:SS.SSS或整数毫秒:

[DisplayName("Delay WebTest")]
[Description("Delay the start of this WebTest by a certain amount of time.")]
public class DelayWebTest : WebTestPlugin
{
    [Description("Time to delay this WebTest, in HH:MM:SS.SSS time format or in ms (e.g. 00:01:23.456 or 83456 for 1m 23.456s delay)")]
    public string Delay { get; set; }

    public override void PreWebTest(object sender, PreWebTestEventArgs e)
    {
        DateTime start;
        // Make sure this works when not in a load test
        if (!e.WebTest.Context.ContainsKey("$LoadTestUserContext"))
            start = DateTime.Now;
        else
            start = (DateTime)(e.WebTest.Context[LoadTestStartTime.LoadTestStartTimeContextParameterName]);

        TimeSpan elapsed = DateTime.Now - start;
        TimeSpan delay;
        // Support {{context parameter}} substitutions
        if (Delay.StartsWith("{{") && Delay.EndsWith("}}"))
        {
            string key = Delay.Substring(2, Delay.Length - 4);
            object value = e.WebTest.Context[key];
            if (value is TimeSpan) delay = (TimeSpan)value;
            else if (value is int) delay = new TimeSpan(0, 0, 0, 0, (int)value);
            else if (value is string) delay = ParseDelayFromString(value as string);
            else throw new ArgumentException("Delay value must be TimeSpan, int or string.  Found: " + value.GetType());
        }
        else delay = ParseDelayFromString(Delay);

        TimeSpan sleep = delay - elapsed;
        if (sleep > new TimeSpan(0))
        {
            e.WebTest.AddCommentToResult("Current time: " + DateTime.Now);
            e.WebTest.AddCommentToResult("About to sleep for " + sleep);
            System.Threading.Thread.Sleep(sleep);
            e.WebTest.AddCommentToResult("Current time: " + DateTime.Now);
        }
    }

    public static TimeSpan ParseDelayFromString(string s)
    {
        TimeSpan ts;
        if (TimeSpan.TryParse(s, out ts)) return ts;
        int i;
        if (int.TryParse(s, out i)) return new TimeSpan(0, 0, 0, 0, (int)i);
        throw new FormatException("Could not parse value as TimeSpan or int: " + s);
    }
}
这似乎对我有用

但是,它使用Thread.Sleep,这“…不建议用于 web测试是因为它是一个阻塞API,多个web测试可以共享一个线程,因此它可能会对多个vuser产生不利影响。”()第187页

因此,对于单用户负载测试,或者对于虚拟用户数不超过线程数*的小负载来说,这当然是可以的,但是对于更大的负载,它很可能会把结果搞砸


(*我并不声称知道线程模型是如何工作的)

好的,再来一次。不过,没有任何错误检查

LoadTestStartTime负载测试插件将对负载测试本身和负载测试开始时间的引用放入web测试上下文中

public class LoadTestStartTime : ILoadTestPlugin
{
    public const string LoadTestContextParameterName = "$LoadTest";
    public const string LoadTestStartTimeContextParameterName = "$LoadTestStartTime";

    public void Initialize(LoadTest loadTest)
    {
        DateTime startTime = default(DateTime);

        loadTest.LoadTestStarting += (sender, e) => { startTime = DateTime.Now; };

        loadTest.TestStarting += (sender,e) => {
            e.TestContextProperties[LoadTestContextParameterName] = loadTest;
            e.TestContextProperties[LoadTestStartTimeContextParameterName] = startTime;
        };
    }
}
DelayWebTest web测试插件必须附加到包含一个虚拟请求的新web测试(虚拟请求将不会执行)。这个新的web测试必须作为“初始化测试”添加到负载测试场景测试组合中

插件从上下文参数读取延迟时间,然后将场景的当前负载设置为0。然后,它设置一个计时器,在正确计算的延迟后调用事件处理程序,从而恢复负载配置文件,从而允许测试继续进行。它使用锁定,以便只有第一个虚拟用户将在其他用户等待时执行负载配置文件逻辑

public class DelayWebTest : WebTestPlugin
{
    public string ContextParameterName { get; set; }

    private bool completed = false;
    private object _lock = new object();

    public override void PreRequest(object sender, PreRequestEventArgs e)
    {
        e.Instruction = WebTestExecutionInstruction.Skip;
        if (!completed)
        {
            lock (_lock)
            {
                if (!completed)
                {
                    if (e.WebTest.Context.WebTestUserId > 0) return;
                    LoadTest loadTest = (LoadTest)e.WebTest.Context[LoadTestStartTime.LoadTestContextParameterName];
                    DateTime startTime = (DateTime)e.WebTest.Context[LoadTestStartTime.LoadTestStartTimeContextParameterName];
                    TimeSpan delay = TimeSpan.Parse(e.WebTest.Context[ContextParameterName].ToString());
                    TimeSpan timer = delay - (DateTime.Now - startTime);
                    if (timer > default(TimeSpan))
                    {
                        var loadProfile = loadTest.Scenarios[0].LoadProfile.Copy();
                        loadTest.Scenarios[0].CurrentLoad = 0;
                        Timer t = new Timer() { AutoReset = false, Enabled = true, Interval = timer.TotalMilliseconds };
                        t.Elapsed += (_sender, _e) =>
                        {
                            loadTest.Scenarios[0].LoadProfile = loadProfile;
                            t.Stop();
                        };
                        t.Start();
                    }
                    completed = true;
                }
            }
        }
    }
}
似乎有效。50个用户,延迟30秒:


这个答案的主要部分是
线程。Sleep(…)
调用,这是我尝试的第一件事。正如您在回答中所说,它会阻塞整个线程,因此只能对极少数虚拟用户起作用。请在VSPTQRG中提供页码。问题中的解决方法允许我进行所需的测试,因此我不再需要花费时间在这个主题上,但感谢您的想法。问题在于延迟单个web测试,而不是延迟场景