Globally replace obsolete NLog.WarnException using regular expression

I’ve updated NLog ver 2.0 to 4.3.5. After this I’ve noticed a compiler warning that 
WarnException(msg,exc) is obsolete and should be replaced by Warn(exc,msg)

It could be globally replaced using regular expressions 

WarnException\((.*),(.*)\);
to 

Warn($2, $1);

See saved regex in https://regex101.com/r/kL8cR4/1

Advertisements

#nlog, #regex

Is it possible to determine Visual Studio edition during c# compile time

To use MS Fakes shims, I had to conditionally exclude related tests  to allow easily bypass them on Community and Professional Editions of the Visual Studio.
#if !FAKES_NOT_SUPPORTED
[ TestMethod()]
Fakes related code
#endif
I tried to find does edition automatically pre-defined by compiler, but it’s not included in Conditional Compilation Constants

Furthermore,  these constants seems defined in VB only, and not in c# and not updated since VS2008.

The reasons are discussed in “Pre-defined Constants, preprocessor directives, etc… “

The “C# Language Designers” decided to not include constants in the fashion in which C/C++ allows them.  To allow some, or even one, would open a Pandora’s Box of voices suggesting new constants to be added.

But I disagree,  because if the limitation coming from VS , it should provide a way to  determine it in pre-condition.
The related article shows how to check installed Visual Studio on run-time
Unfortunately I didn’t find, is it possible to determine Visual Studio edition  during c# compile time?

#compile-time, #constants, #visual-studio

Microsoft Fakes Test Using TimeZoneInfo shim.

I wanted to create a unit test using MS Fakes Framework to replace TimeZoneInfo with Shim (example how to do it see e.g. “Using shims to isolate your application from other assemblies for unit testing”  )

Initially I found that ShimTimeZoneInfo wasn’t generated. After some search I found that Microsoft made some decisions for us/:

What we’ve seen is that user simply want to shim a few type(s) in it.  Due to this, we selectively shimming the commonly used type in the system/mscorlib.

But they didn’t mention it in the documentation.

The actual classes that are generated can be see in FakesAssemblies .fakesconfig files\ (e.g. mscorlib.4.0.0.0.Fakes.fakesconfig)

Fortunately, you can request the compiler to generate shims for specific objects(http://stackoverflow.com/questions/16154182/shims-are-not-generated-for-net-methods)

There are more details in “Code generation, compilation, and naming conventions in Microsoft Fakes”. However note that examples have missing version in lines like

<Assembly Name=”System” Version=”4.0.0.0″/>

So do not copy them literally.

You can specify only what you need and disable StubGeneration

mscorlib.fakes:

<Fakes xmlns=”http://schemas.microsoft.com/fakes/2011/“>

<Assembly Name=”mscorlib” Version=”4.0.0.0″ />

<StubGeneration Disable=”true”/>

<ShimGeneration>

<Add FullName=”System.Environment”/>

<Add FullName=”System.TimeZoneInfo”/>

<Add FullName=”System.DateTime”/>

</ShimGeneration>

</Fakes>

My code also used DateTime.ToUniversalTime, but even ShimDateTime class was generated, particular ShimDateTime.ToUniversalTime was not generated. I haven’t found a way to generate it.

After decompiling I found that the method is a wrapper of TimeZoneInfo method

[__DynamicallyInvokable]

public DateTime ToUniversalTime()

{

return TimeZoneInfo.ConvertTimeToUtc(this , TimeZoneInfoOptions.NoThrowOnInvalidTime);

}

but the overload DateTime ConvertTimeToUtc( DateTime dateTime, TimeZoneInfoOptions flags) is internal (Shim has methods for public overloads static public DateTime ConvertTimeToUtc(DateTime dateTime) and static public DateTime ConvertTimeToUtc( DateTime dateTime, TimeZoneInfo sourceTimeZone))

I’ve had to change in my code

DateTime utcTime = inputDateTime.ToUniversalTime();

to

DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(inputDateTime);

to make it testable.

Because Fakes are available in VS Premium/Ultimate editions 2012/2013 and Enterprise 2015(i.e not available in Community and Professional Editions) I wrapped the test methods in #if !FAKES_NOT_SUPPORTED conditions, to allow easily exclude them on Community and Professional Editions

#if !FAKES_NOT_SUPPORTED

[ TestMethod()]

public void ConvertServerTimeToTimeZoneTimeTest()

{

DateTime inputDateTime = DateTime.Now;

string zoneId = “China Standard Time”;

DateTime timeZoneTime;

//Act

using ( ShimsContext.Create()) //Uses Fakes assembly because TimeZoneInfo may change depending on daylight saving,

{ // hook delegate to the shim method to redirect

TimeZoneInfo.ConvertTimeFromUtc(utcTime, timeInfo);

ShimTimeZoneInfo.ConvertTimeToUtcDateTime = (inputTime) => inputTime.AddHours(-10);

ShimTimeZoneInfo.ConvertTimeFromUtcDateTimeTimeZoneInfo = (utcTime, timeInfo) => utcTime.AddHours(+8);

//Act

timeZoneTime = DateTimeHelper.ConvertServerTimeToTimeZoneTime(inputDateTime, zoneId, true);

}

//Assert

var diff = timeZoneTime – inputDateTime;

diff.Hours.Should().Be(-2);

}

}

#endif //!FAKES_NOT_SUPPORTED

To run Fakes, it’s required to replace legacy MStest.exe test  runner with new VSTest.Console.exe- see my post Replace MSTest to VSTest to support Fakes.

It also was required to do changes in build script, upgrade to latest versions OpenCover and NSubstitute.

#fakes-shims-test

NSubstitute AmbiguousArgumentsException: Cannot determine argument specifications to use.

I had a few tests that failed with error  

NSubstitute.Exceptions.AmbiguousArgumentsException: Cannot determine argument specifications to use. Please use specifications for all arguments of the same type.
They are similar to http://stackoverflow.com/questions/26805420/nsubstitute-testfixture-1-causes-ambiguousargumentsexception-in-testfixture-2.

I installed the latest version of NSubstitute, but it didn’t help.

As it was advised by David, the errors were caused by calls to non-substituted methods with Args.* parameters. Arg.Any were passed to actual code methods, that where called without Returns or Received parameters.

E.g.

providerOperationsCache.PartnerOperationsInfoForThumbPrint(Arg.Any<string>());

The errors did not happened  when Microsoft tests were running under  MSTest, but started when I switched to VSTest.Console.
To scan my test library I used search with regular expression to find rows with Arg.Any but not Arg.Any following by Returns or preceding by Received

(?=^.*Arg.*$)(?=^((?!Arg.*\.Returns).)*$)^((?!\.Received\(.*Arg.).)*$

It’s not bullet proof filter( e.g it doesn’t exclude multi line statements), but it helped to reduce number of calls to check.

#nsubstitute, #tests, #vstest

Replace MSTest to VSTest to support Fakes

I’ve created a unit test using MS Fakes Framework. When I tried to run it from the build script, I’ve got an error:
Test method DateTimeHelperTests.ConvertServerTimeToTimeZoneTimeTest threw exception:
Microsoft.QualityTools.Testing.Fakes.UnitTestIsolation.UnitTestIsolationException: Failed to resolve profiler path from COR_PROFILER_PATH and COR_PROFILER environment variables.
The answer of
http://stackoverflow.com/questions/26743342/running-a-test-using-shims-on-a-visual-studio-2013-test-agent told that instead of “using mstest.exe  I should have been using vstest.console.exe.”
There are a couple articles that explain the differences between MSTest and VSTest.console.exe.
I’ve created below table to describe parameters that should be changed if you move from MSTest to VSTest.
MSTestExe
VSTest.Console.exe
Comments
C:\Program Files (x86)\Microsoft Visual Studio 14\Common7\IDE\MSTest.exe
C:\Program Files (x86)\Microsoft Visual Studio 14\Common7\IDE\CommonExtensions\Microsoft\ TestWindow\VSTest.Console.exe
Full Path for typical installation
mstest /testcontainer:tests.dll
Vstest.console.exe myTestFile.dll myOtherTestFile.dll
Pass test.dll
/resultsfile:testResults.trx
/Logger:trx
TestResults\UserName_MachineName 2016-04-07 18_12_02.trx
/category:!Broken
/TestCaseFilter:”TestCategory!=Broken”
  /testsettings:Local.TestSettings
/Settings:[file name] e.g.
 /Settings:Local.RunSettings
mstest /testcontainer: “C:\TestProject2\myTestFile.dll” /testsettings:Local.TestSettings /category:!Broken /resultsfile:testResults.trx
vstest.console.exe  “C:\TestProject2\myTestFile.dll /Settings:Local.RunSettings /TestCaseFilter:”TestCategory=!Broken” /Logger:trx
Full example
 Tests.runsettings
<!– MSTest adapter –>
<MSTest>
<MapInconclusiveToFailed>True </MapInconclusiveToFailed>
<CaptureTraceOutput>false</CaptureTraceOutput>
<DeleteDeploymentDirectoryAfterTestRunIsComplete> False </DeleteDeploymentDirectoryAfterTestRunIsComplete>
<DeploymentEnabled>False</DeploymentEnabled>
</MSTest>
</RunSettings>
RunSettings for vstest.console adapter
/test:[test name]
to run multiple tests, use the /test option multiple times.
TestClass matches if the name Contains pattern
/Tests:[test name]
To provide multiple values, separate them by commas. Example: /Tests:TestMethod1,testMethod2
Classes and Methods matches if the name contains pattern
Also VSTest is running all tests in a single thread, so there is no proper isolation between tests and settings in one tests may effect subsequent tests.
I had to fix a few tests before the whole test project passed under VSTest.

#fakes, #unit-tests, #vstest

Global Convertion from MStest Assert to FluentAssertions

I found that FluentAssertions http://www.fluentassertions.com/ provide more descriptive logs in case of assertion failure.
However most of our test methods use MSTest Assert class.
For example statement
 Assert.IsTrue(string.IsNullOrEmpty(discountItemRecord.DiscountCode));
should  be changed to
(string.IsNullOrEmpty(discountItemRecord.DiscountCode)).Should().BeTrue();
They can be easily converted with the help of Visual Studio Replace. Just  select “use Regular Expressions”
For example
Search for:   \s*Assert.IsTrue\((.*)\);             replace to:      ($1).Should().BeTrue();
Search for:   \s*Assert.IsFalse\((.*)\);            replace to:      ($1).Should().BeFalse();
Search for:   \s*Assert.IsNotNull\((.*)\);        replace to:   ($1).Should().NotBeNull();
Search for:  (\s*)Assert.AreEqual\((.*),(.*)\);replace to:    $1($3).Should().Be($2);
I’ve used only most common asserts,that we are using,but they can be extended for other asserts.
Example of regular expression can be found on regex101

#fluentassertions, #regex, #unit-tests

2 options to write tests for WCF Services

When writing Integration Tests for  WCF Services, you have 2 options to access SUT(system under test)
1. Inproc – Test Classes are calling methods from application DLLs directly.
2. External – Tests are calling external services using client proxy with specified URL.

If you own the code of the service, the Inproc method is preferred as it is allow to test units rather  the whole object as black-box.

If your tests are external clients of the service determined by URL, you need to have the service installed somewhere, e.g. on the test server.
So you need to use your services URL to run your external tests.

I’ve asked our team in a future when creating new/modifying existing test methods to use inproc approach rather than external clients.