Есть ли способ заставить тесты пользовательского интерфейса MsTest / Coded каждый раз запускаться в новом случайном порядке? - PullRequest
3 голосов
/ 30 марта 2011

Аналогично этому для Java: Как сделать так, чтобы мои тесты JUnit выполнялись в случайном порядке?

И наоборот для .Net: http://blogs.msdn.com/b/slange/archive/2010/06/02/ordering-method-execution-of-a-coded-ui-test.aspx

Моя причина та же, что и в первой ссылке - я хочу раскрыть любые зависимости между тестами, перетасовывая порядок при каждом запуске.

Можно ли это сделать? Я должен использовать MSTest, потому что мои тесты управляют GUI - они используют Coded UI.

Ответы [ 2 ]

3 голосов
/ 11 августа 2012

Поскольку на этот вопрос не было ответа, я сделаю удар.

Я не знаю, имеет ли это встроенная среда тестирования, но я бы просто сам ее кодировал. Самым простым способом может быть написание тестового метода, который вызывает все другие тестовые методы в случайном порядке. Вы можете быть полностью творческими, когда будете это делать, вам просто нужно установить для Playback.PlaybackSettings.ContinueOnError значение true, чтобы общий тест не завершился неудачей, если один тест не пройден.

1 голос
/ 05 октября 2012

Мне нужно что-то подобное, так что это может дать вам или любому другому преимущество.Вы можете просто указать это как собственный класс тестирования, и он будет автоматически запускать каждый другой метод модульного теста в той же сборке один раз в классах модульных тестов со случайным порядком охвата.

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Company.UnitTests
{
    [TestClass]
    public class RandomizerTest
    {
        private class TestClassProxy
        {
            public object Instance { get; set; }
            public Type Type { get; set; }
            public Action ClassCleanup { get; set; }
            public Action<TestContext> ClassInitialize { get; set; }
            public Action TestCleanup { get; set; }
            public Action TestInitialize { get; set; }
            public List<Action> TestMethods { get; set; }
        }

        [TestMethod]
        public void TestRandom()
        {
            // ARRANGE

            // attributes we'll be using to build our proxies (change these for NInject, other UT frameworks)
            var classInitializeAttributeType = typeof (ClassInitializeAttribute);
            var classCleanupAttributeType = typeof (ClassCleanupAttribute);
            var testInitializeAttributeType = typeof (TestInitializeAttribute);
            var testCleanupAttributeType = typeof (TestCleanupAttribute);
            var testMethodAttributeType = typeof (TestMethodAttribute);

            var proxies = (
                              from type in Assembly.GetExecutingAssembly().GetTypes()
                              where
                                  type != typeof (RandomizerTest) && // don't include this class (infinite-loop)
                                  type.GetCustomAttributes(typeof (TestClassAttribute), false).Length > 0 // only classes attributed with [TestClass]
                              let methods = type.GetMethods() // keep the methods for re-use
                              let instance = Activator.CreateInstance(type)
                              select new TestClassProxy
                              {
                                  Type = type,
                                  Instance = instance,
                                  ClassInitialize = // select and wrap the method invokes inside an Action for re-use
                                      methods
                                          .Where(λ =>
                                                 λ.GetCustomAttributes(classInitializeAttributeType, false).Any())
                                          .Select(λ => (Action<TestContext>) (tc => λ.Invoke(instance, new object[] { tc })))
                                          .FirstOrDefault() ?? delegate { },
                                  ClassCleanup =
                                      methods
                                          .Where(λ =>
                                                 λ.GetCustomAttributes(classCleanupAttributeType, false).Any())
                                          .Select(λ => (Action) (() => λ.Invoke(instance, null)))
                                          .FirstOrDefault() ?? delegate { },
                                  TestInitialize =
                                      methods
                                          .Where(λ =>
                                                 λ.GetCustomAttributes(testInitializeAttributeType, false).Any())
                                          .Select(λ => (Action) (() => λ.Invoke(instance, null)))
                                          .FirstOrDefault() ?? delegate { },
                                  TestCleanup =
                                      methods
                                          .Where(λ =>
                                                 λ.GetCustomAttributes(testCleanupAttributeType, false).Any())
                                          .Select(λ => (Action) (() => λ.Invoke(instance, null)))
                                          .FirstOrDefault() ?? delegate { },
                                  TestMethods =
                                      methods
                                      .Where(λ =>
                                             λ.GetCustomAttributes(testMethodAttributeType, false).Any())
                                      .Select(λ => (Action) (() => λ.Invoke(instance, null))).ToList(),
                              }).ToList();

            var random = new Random();

            // ACT

            // Note that the following may not work depending on how you developed your unit tests. 
            // If they're sharing state in any way (SQL DB, etc.) this may not be what you want.
            // If that's the case alter the code below to only randomly sample test methods inside each class 
            //   so that you can isolate tests per test class.
            // This methodology assumes the cardinal rule: All unit tests are atomic. (given their proper setup/teardown)
            // Plus if you're testing in a random order this is likely what you're after anyway.

            // initialize all classes
            foreach (var testClassProxy in proxies)
            {
                testClassProxy.ClassInitialize(null);
            }

            // run all test methods in a random order spanning all test classes until we run out 
            while (proxies.Count > 0)
            {
                // get random test class proxy
                var proxy = proxies[random.Next(0, proxies.Count)];

                // get random test method from proxy
                var testMethod = proxy.TestMethods[random.Next(0, proxy.TestMethods.Count)];

                // run test initialize
                proxy.TestInitialize();

                // run test method
                testMethod(); // (ASSERT)

                // run test cleanup
                proxy.TestCleanup();

                // remove test method from processing
                proxy.TestMethods.Remove(testMethod);

                // still have methods?
                if (proxy.TestMethods.Count > 0)
                {
                    continue;
                }

                // no, run class cleanup routine
                proxy.ClassCleanup();

                // remove the proxy from processing
                proxies.Remove(proxy);
            }
        }
    }
}
...