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

#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();\n
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.

Number of Unit test projects in Visual Studio solution

Some time ago I have discussion with my co-worker  how to organize test projects. 
Should we have a single test project that does all sorts of things and references every project?
It is good to have one integration test dll, but for unit tests, what is the point merging everything into one.

In ideal world I agree that small independent projects are better. Unfortunately we have  solution size limitations 
However, Visual Studio performance quickly degrades as the number of projects increases. Around the 40 project mark compilation becomes an obstacle to compiling and running the tests, so larger projects may benefit from consolidating test projects.
  • Single solution. If you work on a small system, create a single solution and place all of your projects within it.
  • Partitioned solution. If you work on a large system, use multiple solutions to group related projects together. Create solutions to logically group subsets of projects that a developer would be most likely to modify as a set, and then create one master solution to contain all of your projects. This approach reduces the amount of data that needs to be pulled from source control when you only need to work on specific projects.
  • Multiple solutions. If you are working on a very large system that requires dozens of projects or more, use multiple solutions to work on sub-systems but for dependency mapping and performance reasons do not create a master solution that contains all projects.
At the moment we decided to go with one huge integration test and one huge unit test projects.
And we constantly trying to keep reasonable (not too many) number of projects in the main solution. Unfortunately this number is quite big – 70+. 

Override ToString() using Json serialization or something else.

When creating a new data class, it’s a good idea to override ToString() method to output most of the data.
It will help to see details in logs.

The only exception if the class has a sensitive data like CreditCard number or password.
For DataContract classes just use

public override string ToString()
              {
                      //Use JSON as the simplest serializer
                      string sRet = this.ToExtJsJsonItem();
                      return sRet;
              }
 
Sometimes it is useful to create extensions to standard .Net classes.
E.g. In CookieHelper class I’ve created
  public static string ToJsonString( this HttpCookie httpCookie)
        {
            string sRet = httpCookie.ToExtJsJsonItem();
            return sRet;
        }
 
The actual extension we are using was written by Nikita Pinchuk
      public static string ToExtJsJsonItem( this object item)
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(item.GetType());
            using ( MemoryStream ms = new MemoryStream ())
            {
                serializer.WriteObject(ms, item);
                StringBuilder sb = new StringBuilder ();

                sb.Append( Encoding.UTF8.GetString(ms.ToArray()));

                return sb.ToString();
            }
        }
 
For non DataContract classes the extension method may not work-it could cause an error: 
A first chance exception of type ‘System.Runtime.Serialization.InvalidDataContractException’ occurred in System.Runtime.Serialization.dll

In this case you can try  JSON.NET or the JsonValue types (nuget package JsonValue).

Sometimes I am using
 string sRet = this.XmlSerializeSafe();
 
But it is also not working for all types, e.g. 
MyClass cannot be serialized because it does not have a parameterless constructor.
In some places we are using LinqPad’s Dump an arbitrary object To Html String, but we found it is too heavy for logs, plain text is easier to read than HTML.
I haven’t tried yet ServiceStack.Text  C# .NET Extension method: T.Dump();

Deploy PDB files into production to ease exception report investigation.

 

 For a long time I believed that PDB as a part of debugging information should not be included in production deployment. Recently my colleague suggested to copy them to simplify exception investigations. 

 

The following  SO discussion convinced us that it is a good idea  ( at least for web sites).

 http://stackoverflow.com/questions/933883/are-there-any-security-issues-leaving-the-pdb-debug-files-on-the-live-servers

    These files will not be exposed to the public if kept in the right places (websitebin). 

 
 So we decided to deploy the PDBs into production.
 

BTW, if you include PDBs with your deployments, you don’t need to store them in a symbol server,

 as it is suggested in http://www.wintellect.com/CS/blogs/jrobbins/archive/2009/05/11/pdb-files-what-every-developer-must-know.aspx

However we found that  PDBs   were generated not for all DLLs.  After some analysis we believe that MS changed default settings starting from VS 2008 (or may be since VS 2005) and make generation of PDB-only even for release mode. This is why older projects had generation of PDBs disabled.

To change setting in Visual Studio there is an option in the “Project Properties”, “Build”, “Advanced…”.

Change “Debug Info:” to PDB-only.

The screenshots are available in the posthttp://callicode.com/Homeltpagegt/tabid/38/EntryId/24/How-to-disable-pdb-generation-in-Visual-Studio-2008.aspx

 

Related links:
The article http://blog.vuscode.com/malovicn/archive/2007/08/05/releasing-the-build.aspx compares different options for debug and release and confirms that in 2007 pdbonly was the default for release configuration of visual studio   
              

/optimize+ /debug:pdbonly (release configuration of visual studio)

The article Include .pdb files in Web Application Publish for Release mode (VS2012)  wasn’t applicable for us, but may be useful for someone else.