좋아요, 이것에 대한 좋은 정보를 찾았습니다. 일단 초기화되면 변경할 수 없거나 변경하고 싶지 않은 속성을 설정하는 정적 클래스를 호출하는 일련의 단위 테스트가 있습니다.
내 문제는 테스트가 실행되도록 설정된 순서를 적용 할 수 없다는 것입니다. 가능하다면 정적 속성이 신뢰할 수있는 방식으로 설정되는 방식으로 실행할 수 있고 Assert를 수행 할 수 있지만 안타깝게도 Microsoft.VisualStudio.TestTools.UnitTesting 프레임 워크는 겉보기에 임의의 순서로 실행합니다. .
그래서이 http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.priorityattribute.aspx 를 찾았 습니다. 설명 섹션에 “이 속성은 테스트 시스템에서 사용되지 않습니다. 사용자 지정 목적으로 사용자에게 제공됩니다. ” 어? 그러면 무슨 소용이 있습니까? 그들은 내가이 멋진 속성을 활용하기 위해 내 자신의 테스트 래퍼를 작성하기를 기대합니까 (그 정도의 노력을 기울이고 싶다면 쉽게 작성할 수 있습니다 …)
그래서, 충분한 폭언; 요컨대, 단위 테스트가 실행되는 순서를 제어하는 방법이 있습니까?
[TestMethod]
[Priority(0)]
등은 작동하지 않는 것 같습니다. 이는 Microsoft가 작동하지 않는다고 말했기 때문에 의미가 있습니다.
또한 “격리 위반”에 대한 의견을 남기지 마십시오. TestClass는 개별 TestMethod가 아닌 내가 테스트중인 것을 분리합니다. 그럼에도 불구하고 각 테스트는 독립적으로 잘 실행될 수 있으며 정적 클래스를 해체 할 방법이 없기 때문에 임의의 순서로 함께 실행할 수 없습니다.
오, “주문 테스트”에 대해서도 알고 있습니다.
답변
테스트를 하나의 거대한 테스트로 병합하면 효과가 있습니다. 테스트 방법을 더 읽기 쉽게 만들기 위해 다음과 같이 할 수 있습니다.
[TestMethod]
public void MyIntegratonTestLikeUnitTest()
{
AssertScenarioA();
AssertScenarioB();
....
}
private void AssertScenarioA()
{
// Assert
}
private void AssertScenarioB()
{
// Assert
}
실제로 당신이 가지고있는 문제는 아마도 구현의 테스트 가능성을 향상시켜야한다고 제안합니다.
답변
당신은 재생 목록을 사용할 수 있습니다
테스트 방법을 마우스 오른쪽 버튼으로 클릭-> 재생 목록에 추가-> 새 재생 목록
실행 순서는 재생 목록에 추가하는 것과 같지만 변경하려면 파일이 있습니다.
답변
지금 쯤 알고 계시 겠지만, 순수 주의자들은 명령 된 테스트를 실행하는 것이 금지되어 있다고 말합니다. 단위 테스트의 경우에 해당 할 수 있습니다. MSTest 및 기타 단위 테스트 프레임 워크는 순수 단위 테스트를 실행하는 데 사용되지만 UI 테스트, 전체 통합 테스트도 실행합니다. 단위 테스트 프레임 워크라고 부르면 안되거나 필요에 따라 사용해야 할 수도 있습니다. 어쨌든 대부분의 사람들이하는 일입니다.
저는 VS2015를 실행 중이며 UI 테스트 (Selenium)를 실행하고 있기 때문에 지정된 순서대로 테스트를 실행해야합니다.
우선 순위 -아무것도하지 않음
이 속성은 테스트 시스템에서 사용되지 않습니다. 사용자 정의 목적으로 사용자에게 제공됩니다.
orderedtest- 작동하지만 다음과 같은 이유로 권장하지 않습니다.
- orderedtest 가 실행되어야 위해 테스트를 나열하는 텍스트 파일. 메소드 이름을 변경하는 경우 파일을 수정해야합니다.
- 테스트 실행 순서는 클래스 내에서 존중됩니다. 어떤 클래스가 먼저 테스트를 실행하는지 주문할 수 없습니다.
- orderedtest의 파일은 디버그 또는 릴리스 중, 구성에 바인딩
- 여러 개의 정렬 된 테스트 파일을 가질 수 있지만 지정된 방법을 다른 정렬 된 테스트 파일 에서 반복 할 수 없습니다 . 따라서 디버그 용과 릴리스 용으로 orderedtest 파일 하나를 가질 수 없습니다 .
이 스레드의 다른 제안은 흥미롭지 만 테스트 탐색기에서 테스트 진행 상황을 추적 할 수있는 기능이 없습니다.
당신은 순수 주의자가 조언 할 해결책을 남겼지 만 실제로 작동하는 해결책은 선언 순서로 정렬합니다 .
MSTest 실행자는 선언 순서를 관리하는 interop을 사용하며이 트릭은 Microsoft가 테스트 실행기 코드를 변경할 때까지 작동합니다.
즉, 처음에 선언 된 테스트 메서드가 두 번째 위치에 선언 된 메서드보다 먼저 실행됩니다.
당신의 삶을 더 쉽게 만들기 위해 선언 순서는 테스트 탐색기에 표시된 알파벳 순서와 일치해야합니다.
- A010_FirstTest
- A020_SecondTest
- 기타
- A100_TenthTest
오래되고 테스트 된 규칙을 강력히 제안합니다.
- 나중에 테스트 방법을 삽입해야하므로 10 단계를 사용하십시오.
- 테스트 번호 사이에 넉넉한 단계를 사용하여 테스트 번호를 다시 매길 필요가 없습니다.
- 10 개 이상의 테스트를 실행하는 경우 3 자리 숫자를 사용하여 테스트 번호를 매 깁니다.
- 100 개 이상의 테스트를 실행하는 경우 4 자리 숫자를 사용하여 테스트 번호를 매 깁니다.
매우 중요
선언 순서대로 테스트를 실행 하려면 테스트 탐색기에서 모두 실행 을 사용해야합니다 .
3 개의 테스트 클래스가 있다고 가정합니다 (제 경우에는 Chrome, Firefox 및 Edge에 대한 테스트). 주어진 클래스를 선택하고 Run Selected Tests를 마우스 오른쪽 버튼으로 클릭 하면 일반적으로 마지막 위치에 선언 된 메서드를 실행하여 시작됩니다.
다시 말하지만, 선언 된 순서 와 상장 된 순서 가 일치해야합니다. 그렇지 않으면 곧 큰 문제가 발생할 것입니다.
답변
ClassInitialize
속성 메서드를 언급하는 사람이 보이지 않습니다 . 속성은 매우 간단합니다.
단위 테스트가 실행될 환경의 측면을 준비하기 위해 [ClassInitialize()]
또는 [TestInitialize()]
특성으로 표시된 메서드를 만듭니다 . 이것의 목적은 단위 테스트를 실행하기위한 알려진 상태를 설정하는 것입니다. 예를 들어 [ClassInitialize()]
또는 [TestInitialize()]
방법을 사용하여 테스트에서 사용할 특정 데이터 파일을 복사, 변경 또는 생성 할 수 있습니다.
[ClassCleanup()]
또는 [TestCleanUp{}]
특성으로 표시된 메서드를 만들어 테스트가 실행 된 후 환경을 알려진 상태로 되돌립니다. 이것은 폴더의 파일을 삭제하거나 데이터베이스를 알려진 상태로 되 돌리는 것을 의미 할 수 있습니다. 이에 대한 예는 주문 입력 애플리케이션에서 사용되는 방법을 테스트 한 후 재고 데이터베이스를 초기 상태로 재설정하는 것입니다.
-
[ClassInitialize()]
ClassInitialize
클래스에서 첫 번째 테스트를 실행하기 전에 코드를 실행하는 데 사용 합니다. -
[ClassCleanUp()]
ClassCleanup
클래스의 모든 테스트가 실행 된 후 코드를 실행하는 데 사용 합니다. -
[TestInitialize()]
TestInitialize
각 테스트를 실행하기 전에 코드를 실행하는 데 사용 합니다. -
[TestCleanUp()]
TestCleanup
각 테스트가 실행 된 후 코드를 실행하는 데 사용 합니다.
답변
Visual Studio 테스트 프레임 워크가 제공하는 Ordered Test 기능을 이미 언급 했으므로 무시하겠습니다. 또한이 정적 클래스를 테스트하기 위해 수행하려는 작업이 “나쁜 생각”이라는 것을 알고있는 것 같으므로 무시하겠습니다.
대신 원하는 순서로 테스트가 실행되도록 실제로 보장 할 수있는 방법에 초점을 맞 춥니 다. 하나의 옵션 (@gaog에서 제공)은 “하나의 테스트 방법, 많은 테스트 함수”로, TestMethod
속성이 표시된 단일 함수 내에서 원하는 순서로 테스트 함수를 호출합니다 . 이것이 가장 간단한 방법이며 유일한 단점은 첫 번째 테스트 기능이 실패하면 나머지 테스트 기능이 실행되지 않는다는 것 입니다.
상황에 대한 설명과 함께 이것이 사용하도록 제안하는 솔루션입니다.
굵게 표시된 부분이 문제인 경우 내장 된 데이터 기반 테스트 기능을 활용하여 격리 된 테스트를 순서대로 실행할 수 있습니다. 더 복잡하고 약간 더러워 보이지만 작업이 완료됩니다.
간단히 말해, 테스트를 실행해야하는 순서와 실제로 테스트 기능을 포함하는 함수의 이름을 제어하는 데이터 소스 (예 : CSV 파일 또는 데이터베이스 테이블)를 정의합니다. 그런 다음 해당 데이터 소스를 데이터 기반 테스트에 연결하고 순차 읽기 옵션을 사용하고 원하는 순서대로 개별 테스트로 함수를 실행합니다.
[TestClass]
public class OrderedTests
{
public TestContext TestContext { get; set; }
private const string _OrderedTestFilename = "TestList.csv";
[TestMethod]
[DeploymentItem(_OrderedTestFilename)]
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", _OrderedTestFilename, _OrderedTestFilename, DataAccessMethod.Sequential)]
public void OrderedTests()
{
var methodName = (string)TestContext.DataRow[0];
var method = GetType().GetMethod(methodName);
method.Invoke(this, new object[] { });
}
public void Method_01()
{
Assert.IsTrue(true);
}
public void Method_02()
{
Assert.IsTrue(false);
}
public void Method_03()
{
Assert.IsTrue(true);
}
}
내 예에서는 출력에 복사되는 TestList.csv라는 지원 파일이 있습니다. 다음과 같이 보입니다.
TestName
Method_01
Method_02
Method_03
테스트는 지정한 순서대로 일반적인 테스트 격리 상태로 실행됩니다 (즉, 하나가 실패하더라도 나머지는 여전히 실행되지만 정적 클래스를 공유 함).
위의 내용은 실제로 기본 아이디어 일뿐입니다. 프로덕션에서 사용한다면 테스트가 실행되기 전에 동적으로 테스트 함수 이름과 순서를 생성합니다. 찾은 PriorityAttribute와 간단한 리플렉션 코드를 활용하여 클래스에서 테스트 메서드를 추출하고 적절하게 정렬 한 다음 해당 순서를 데이터 소스에 기록 할 수 있습니다.
답변
다음은 어떤 이유로 든 MS Ordered Tests 프레임 워크와 독립적으로 정렬 된 테스트를 설정하고 실행하는 데 사용할 수있는 클래스입니다.
원래 테스트 프레임 워크는 정렬 된 테스트 목록 만 단일 테스트로 간주하므로 [TestInitalize ()] Init ()와 같은 초기화 / 정리는 전체 집합 전후에만 호출됩니다.
용법:
[TestMethod] // place only on the list--not the individuals
public void OrderedStepsTest()
{
OrderedTest.Run(TestContext, new List<OrderedTest>
{
new OrderedTest ( T10_Reset_Database, false ),
new OrderedTest ( T20_LoginUser1, false ),
new OrderedTest ( T30_DoLoginUser1Task1, true ), // continue on failure
new OrderedTest ( T40_DoLoginUser1Task2, true ), // continue on failure
// ...
});
}
이행:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace UnitTests.Utility
{
/// <summary>
/// Define and Run a list of ordered tests.
/// 2016/08/25: Posted to SO by crokusek
/// </summary>
public class OrderedTest
{
/// <summary>Test Method to run</summary>
public Action TestMethod { get; private set; }
/// <summary>Flag indicating whether testing should continue with the next test if the current one fails</summary>
public bool ContinueOnFailure { get; private set; }
/// <summary>Any Exception thrown by the test</summary>
public Exception ExceptionResult;
/// <summary>
/// Constructor
/// </summary>
/// <param name="testMethod"></param>
/// <param name="continueOnFailure">True to continue with the next test if this test fails</param>
public OrderedTest(Action testMethod, bool continueOnFailure = false)
{
TestMethod = testMethod;
ContinueOnFailure = continueOnFailure;
}
/// <summary>
/// Run the test saving any exception within ExceptionResult
/// Throw to the caller only if ContinueOnFailure == false
/// </summary>
/// <param name="testContextOpt"></param>
public void Run()
{
try
{
TestMethod();
}
catch (Exception ex)
{
ExceptionResult = ex;
throw;
}
}
/// <summary>
/// Run a list of OrderedTest's
/// </summary>
static public void Run(TestContext testContext, List<OrderedTest> tests)
{
Stopwatch overallStopWatch = new Stopwatch();
overallStopWatch.Start();
List<Exception> exceptions = new List<Exception>();
int testsAttempted = 0;
for (int i = 0; i < tests.Count; i++)
{
OrderedTest test = tests[i];
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
testContext.WriteLine("Starting ordered test step ({0} of {1}) '{2}' at {3}...\n",
i + 1,
tests.Count,
test.TestMethod.Method,
DateTime.Now.ToString("G"));
try
{
testsAttempted++;
test.Run();
}
catch
{
if (!test.ContinueOnFailure)
break;
}
finally
{
Exception testEx = test.ExceptionResult;
if (testEx != null) // capture any "continue on fail" exception
exceptions.Add(testEx);
testContext.WriteLine("\n{0} ordered test step {1} of {2} '{3}' in {4} at {5}{6}\n",
testEx != null ? "Error: Failed" : "Successfully completed",
i + 1,
tests.Count,
test.TestMethod.Method,
stopWatch.ElapsedMilliseconds > 1000
? (stopWatch.ElapsedMilliseconds * .001) + "s"
: stopWatch.ElapsedMilliseconds + "ms",
DateTime.Now.ToString("G"),
testEx != null
? "\nException: " + testEx.Message +
"\nStackTrace: " + testEx.StackTrace +
"\nContinueOnFailure: " + test.ContinueOnFailure
: "");
}
}
testContext.WriteLine("Completed running {0} of {1} ordered tests with a total of {2} error(s) at {3} in {4}",
testsAttempted,
tests.Count,
exceptions.Count,
DateTime.Now.ToString("G"),
overallStopWatch.ElapsedMilliseconds > 1000
? (overallStopWatch.ElapsedMilliseconds * .001) + "s"
: overallStopWatch.ElapsedMilliseconds + "ms");
if (exceptions.Any())
{
// Test Explorer prints better msgs with this hierarchy rather than using 1 AggregateException().
throw new Exception(String.Join("; ", exceptions.Select(e => e.Message), new AggregateException(exceptions)));
}
}
}
}
답변
테스트 순서는 말씀 드리지 않겠습니다. 죄송합니다. 다른 사람들은 이미 해냈습니다. 또한 “정렬 된 테스트”에 대해 알고 있다면 문제에 대한 MS VS의 응답입니다. 나는 그 주문 테스트가 재미 없다는 것을 알고 있습니다. 그러나 그들은 그것이 “그것”일 것이라고 생각했고 MSTest에는 더 이상 그것에 대해 아무것도 없습니다.
나는 당신의 가정 중 하나에 대해 씁니다.
정적 클래스를 해체 할 방법이 없기 때문입니다.
정적 클래스가 코드 외부의 일부 프로세스 전체 외부 상태 (예 : 나머지 코드에 의해 P / Invoked되는 관리되지 않는 네이티브 DLL 라이브러리의 상태) there is no way
를 나타내지 않는 한 , 귀하의 가정 은 사실이 아닙니다.
정적 클래스가 이것을 참조하면 미안합니다. 완벽하게 맞습니다. 나머지는 관련이 없습니다. 그래도 당신이 그렇게 말하지 않았기 때문에 나는 당신의 코드가 “관리”된다고 가정한다.
AppDomain
물건을 생각하고 확인하십시오 . 드물게 필요하지만 사용하고 싶을 때 꼭 필요한 경우입니다.
새 AppDomain을 만들고 여기에서 테스트를 인스턴스화하고 여기에서 테스트 메서드를 실행할 수 있습니다. 관리 코드에서 사용하는 정적 데이터는 여기에서 격리되고 완료되면 AppDomain을 언로드 할 수 있으며 정적이 포함 된 모든 데이터가 사라집니다. 그런 다음 다음 테스트는 다른 appdomain을 초기화합니다.
추적해야하는 외부 상태가 없으면 작동합니다. AppDomains는 관리되는 메모리 만 격리합니다. 모든 네이티브 DLL은 여전히 프로세스별로로드되며 해당 상태는 모든 AppDomain에서 공유됩니다.
또한 appdomains를 생성 / 분리하면 테스트 속도가 느려집니다. 또한 자식 appdomain의 어셈블리 해결에 문제가있을 수 있지만 적절한 양의 재사용 가능한 코드로 해결할 수 있습니다.
또한 자식 AppDomain과 테스트 데이터를주고받는 데 약간의 문제가있을 수 있습니다. 전달 된 객체는 어떤 식 으로든 직렬화 가능해야 MarshalByRef
하거나 또는 등등 이어야합니다 . 교차 도메인을 말하는 것은 거의 IPC와 같습니다.
그러나 여기서주의하세요. 100 % 관리되는 대화입니다. 약간의주의를 기울이고 AppDomain 설정에 약간의 작업을 추가하면 델리게이트를 전달하고 대상 도메인에서 실행할 수도 있습니다. 그런 다음 털이 많은 교차 도메인 설정을 만드는 대신 다음과 같이 테스트를 래핑 할 수 있습니다.
void testmethod()
{
TestAppDomainHelper.Run( () =>
{
// your test code
});
}
또는
[IsolatedAppDomain]
void testmethod()
{
// your test code
}
테스트 프레임 워크가 이러한 래퍼 / 확장 프로그램 생성을 지원하는 경우. 초기 연구와 작업을 마친 후 사용하는 것은 거의 사소한 일입니다.
