Unit Testing an Application with a DAL Generated by SubSonic - unit-testing

I am currently working on an inherited codebase. One of the critical missing pieces is unit testing. I seem to have run into a roadblock while trying to set up some unit tests in NUnit.
I created a separate unit testing project as normal, added the necessary references to SubSonic, NUnit and the various DLLs created by the application and set up a dummy unit test to ensure everything is set up correctly. The problems started when I attempted to reference some of the objects generated by SubSonic. I created this test to list users:
[Test]
public void CanListUsers()
{
UserCollection users = UserController.List(UserController
.Query()
.Where(User.Columns.IsDeleted, false));
Assert.IsNotNull(users);
}
and got this exception:
Can't find the SubSonicService in your
application's config
I fixed that by pulling out the parts of the Web.config that were related to SubSonic into an App.config in the unit testing project. Now, when I rerun the unit tests, I get:
UnitTests.TestClass.CanListUsers:
System.Reflection.TargetInvocationException
: Exception has been thrown by the
target of an invocation. ---->
System.Configuration.ConfigurationErrorsException
: Could not load type
'Utility.SqlSubsonicProvider' from
assembly 'System.Web, Version=4.0.0.0,
Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a'.
This exception has me confused because SqlSubsonicProvider is a class in the Utility namespace and can be seen in Object Browser so why is it being looked for in System.Web?
Edit: Okay, I have rearranged the namespaces in the solution so that they make more sense. I think that fixed the above error. Unfortunately I'm now getting this error:
ChannelMechanics.UnitTests.TestClass.CanListVendors:
System.Reflection.TargetInvocationException : Exception has been thrown by the target
of an invocation.
----> System.NullReferenceException : Object reference not set to an instance of
an object.
What's even stranger is that the unit test passes when I use Visual Studio's "Attach to Process" command in the Debug menu and attach to the NUnit GUI. My theory was that the null object would be easily spotted from within the debugger.
If it helps, my App.config looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="SubSonicService"
type="SubSonic.SubSonicSection, SubSonic"
requirePermission="false"/>
</configSections>
<connectionStrings>
<add name="DatabaseConnection"
connectionString="*removed*"/>
</connectionStrings>
<SubSonicService defaultProvider="TestProvider">
<providers>
<clear />
<add name="TestProvider"
type="SubSonic.SqlDataProvider, SubSonic"
connectionStringName="DatabaseConnection"
generatedNamespace="Test"/>
</providers>
</SubSonicService>
</configuration>
The exception details are:
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type,
Boolean publicOnly, Boolean noCheck, Boolean& canBeCached,
RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis,
Boolean fillCache)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly,
Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache)
at System.Activator.CreateInstance[T]()
at SubSonic.ActiveController`2.Query()
at UnitTests.TestClass.CanListVendors() in UnitTests\TestClass.cs:line 59
--NullReferenceException
at DataAccess.Vendor.GetTableSchema() in DataAccess\Generated\Models\Vendor.cs:line 376
at DataAccess.Vendor.SetSQLProps() in DataAccess\Generated\Models\Vendor.cs:line 42
at DataAccess.Vendor..ctor() in DataAccess\Generated\Models\Vendor.cs:line 35
The test that I am running is basically the same as the one listed above except it's Vendors rather than Users that should be getting listed.
[Test]
public void CanListVendors()
{
VendorCollection vendors = VendorController.List(
VendorController
.Query()
.Where(Vendor.Columns.IsDeleted, false));
Assert.IsNotNull(vendors);
}

I would suggest there is a System.Web.Utility namespace, and you get this wrong error message because the compiler "thinks" he has to look inside this namespace for resolving the class.
Please check that your test project is set to target framework "Framework 4" and not "Framework 4 Client Profile".
Missing ".NET Framework 4 Client Profile" as target framework in "New Project" window

This seems to be working now. The only change I made within the project was to create a separate test project using Visual Studio's unit test capabilities. The only other explanation I can think of is that something troublesome got thrown out of memory when I rebooted the computer between yesterday evening and today.
For the benefit of anyone stumbling on this question in the future, here is a summary of the steps I took to get NUnit testing a DAL generated by SubSonic:
Create new class library project.
Add necessary references - I added the DAL, NUnit and SubSonic.
Add an App.config file so that
SubSonic knows where to find the
SubSonic service. All I did for this
was to pull out the parts in
Web.config that were related to
SubSonic.
Add a test class and start adding tests to it.
If your tests are inexplicably failing, make sure the "Copy to Output Directory" is set to "Copy if newer" for the App.config that was added, make sure the provider name in App.config matches the provider name used in the DAL classes and, if all else fails, reboot!

Do you always have SubSonic not Subsonic?
This is the relevant section from my nunit projects config file which works...
<configSections>
<section name="SubSonicService"
type="SubSonic.SubSonicSection, SubSonic"
requirePermission="false"/>
</configSections>
<SubSonicService defaultProvider="TAProvider">
<providers>
<clear />
<add name="TAProvider"
type="SubSonic.SqlDataProvider, SubSonic"
connectionStringName="TATesting"
generatedNamespace="DALTA"/>
</providers>
</SubSonicService>

Related

Roslyn Source Generators Unit Testing error CS0234: The type or namespace name 'Console' does not exist in the namespace 'System'

I am trying to write a unit test for a simple Roslyn Source Generator based on the example here.
Successfully ran both MsTest as well XUnit Tests as demonstrated in the Section B of the Unit testing of generators in the cookbook here.
My full solution that I ran is here for you to see.
The problem is as follows. I added a bit more code to the generator. It now looks as below.
context.AddSource("MyGeneratedFile.cs", SourceText.From(#"
namespace GeneratedNamespace
{
public class GeneratedClass
{
public static void GeneratedMethod()
{
// generated code
System.Console.WriteLine(""Hello..."");
}
}
}", Encoding.UTF8));
}
Note that I added the following line
System.Console.WriteLine(""Hello..."");
Now when I run the test, the test fails. Looking into the diagnostic object I see the following error.
error CS0234: The type or namespace name 'Console' does not exist in the namespace 'System' (are you missing an assembly reference?)
Definitely I am missing something.
New to Roslyn stuff, so how can I make the test pass? How do I add some references to the assembly that holds System namespace?
One way is to simply comment out the offending line, and yes its passing that way. But I am curious. How do I attach the required assembly that it is looking for?
Update
As #Youssef13 suggested, I added the MetadataReference for the console type
So that issue is gone, but now the following appears.
error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
I tried to add another MetadataReference for System.Object here, but this did not resolve it, the above persists.
How do I add a ref to System.Runtime?
Update 2.
Now I resolved it by adding the ref as follows. Take a look at it here.
var systemRuntime = Assembly.Load("System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
var systemRuntimeRef = MetadataReference.CreateFromFile(systemRuntime.Location);
I very very recommend the "Solution A" of the unit testing from the document you linked. But for "Solution B", you'll have to provide the assembly containing Console class. You can do that using:
MetadataReference.CreateFromFile(typeof(Console).Assembly.Location)
There is an IEnumerable<MetadataReference> parameter for CSharpCompilation.Create.
The testing library, however, does include everything you need for whatever .NET version you want. Which is more flexible.

Why doesn't the log4net XmlConfigurator attribute work for my unit tests

I'm using log4net, trying to get logging in my unit tests. If I manually call
log4net.Config.XmlConfigurator.Configure();
Since that works, that seems to eliminate all of the "bad config, config location" issues.
it works, but there are a large number of test classes, so that is not good.
I added
[assembly: log4net.Config.XmlConfigurator(Watch=true)]
to the assemblyinfo of my test project, but when I run (either via native MSTest, or Resharper test runner) I get no logging.
Help?
Source
[AssemblyInitialize()]
public static void MyTestInitialize(TestContext testContext)
{
// Take care the log4net.config file is added to the deployment files of the testconfig
FileInfo fileInfo;
string fullPath = Path.Combine(System.Environment.CurrentDirectory, "log4net.config");
fileInfo = new FileInfo(fullPath);
As it says in the documentation for assembly attributes
Therefore if you use configuration attributes you must invoke log4net
to allow it to read the attributes. A simple call to
LogManager.GetLogger will cause the attributes on the calling assembly
to be read and processed. Therefore it is imperative to make a logging
call as early as possible during the application start-up, and
certainly before any external assemblies have been loaded and invoked.
Because the unit test runners load the test assembly in order to find and the tests, it isn't possible to initialise log4net using an assembly attribute in unit test projects, and you will have to use the XmlConfigurator.
Edit: as linked in a comment by OP this can be done in one place for the whole test project by using the AssemblyInitializeAttribute

Watin and ApartmentState.STA

Issue: "The CurrentThread needs to have it's ApartmentState set to ApartmentState.STA to be able to automate Internet Explorer."
First of all i have read all the solutions to the problems above and none works for me.May be i am missing something. I have tried adding Execution Thread entry into my app.config, also tried setting STAThread attribute and i am still facing the same exception as stated above.
Tools: Visual Studio 2010, Watin 2.1, c#
Scenario: Trying to run a unit test [watin script in c#] from a web application upon a button click. But the above exception is thrown when the script is about to launch IE on the following line :
IE mybrowser = new IE ("SomeURL here");
Any Thoughts ?
Got it from a friend. We actually dont have to add any app.config entry. Just start the thread in a single state. In my case, i wrote the following code in my button click handler:
System.Threading.Thread th = new Thread(new ThreadStart(Test));
th.SetApartmentState(ApartmentState.STA);
th.Start();
th.Join();
and i moved the call to unit test in the private. TEST method as follows:
private void Test()
{
var som = new Project.ClassName();
som.MethodToExecute();
}
What does your App.Config look like?
<NUnit>
<TestRunner>
<!-- Valid values are STA,MTA. Others ignored. -->
<add key="ApartmentState" value="STA"/>
</TestRunner>
</NUnit>
The above works for me on Win7, IE9 (32bit), and Watin2.1. It also works on WinXP, IE8, WatiN 2.1. I'm 99% sure it worked just fine on previous versions of WatiN as well. No other ApartmentState changes were needed.
Simply add [assembly: RequiresSTA] at the top of your file or at the entry point of your project.
I had already done the app.config changes
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="NUnit">
<section name="TestRunner" type="System.Configuration.NameValueSectionHandler" />
</sectionGroup>
</configSections>
<NUnit>
<TestRunner>
<add key="ApartmentState" value="STA" />
</TestRunner>
</NUnit>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="nunit.framework" publicKeyToken="96d09a1eb7f44a77" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.3.13283" newVersion="2.6.3.13283" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
but no dice. I opened AssemblyInfo and added
[assembly: RequiresSTA]
and suddenly, the universe began to function properly again.

Running Unit Test having Operation could destablize the runtime exception at new StandardKernel

In our unit tests where it first load db setting from a singleton class, we have:
IKernel kernel = new StandardKernel(new OurInfrastructureNinjectModule());
_myService = kernel.Get<MyService>(); // To inject a concrete to myService
It runs fine in our mvc application, however, exception threw when it is called by unit tests.
Note: I work at Typemock
Due to changes in security in .NET 4, there was a bug in Typemock Isolator where code running from assemblies marked with AllowPartiallyTrustedCallers (APTCA) or SecurityTransparent attributes would crash with this exception. Ninject, seems like it, is marked with such an attribute.
We had fixed this issue in the latest version, so please download it at http://www.typemock.com.
If your issue persists in the latest version (6.0.9 currently), please contact us via support at typemock.com

iPhone - Retrieving Resources for logical unit tests

I've been following Apple's documentation on writing unit tests for the iPhone, and out of the box, the routine doesn't seem to work. I'm not sure I understand where the unit test is going to get the reference to the application delegate.
My Dependencies are like the following:
My_Program_target -> UnitTesting_target -> UnitTests_bundle
The following code snippet is where the assert fails. I'm very familiar with CPPUNIT, but I'm having trouble understanding how this crosses over.
- (void) testAppDelegate {
id yourApplicationDelegate = [[UIApplication sharedApplication] delegate];
STAssertNotNil(yourApplicationDelegate, #"UIAppliation failed to find the AppDelegate");
}
Additionally:
I've decided in my approach to do a logic test. I'm trying to read in an XML file, but I'm not having luck resolving the bundle, which will provide me with the path by which I can access my file. I've tried pasting in the path output by allBundles, but that path doesn't seem to work either. Below is what I'm executing in my test (you can see the debug statement I'm using to output the paths of the bundles):
NSLog(#"BundlePaths: %#", [NSBundle allBundles]);
NSString * path = [[NSBundle bundleWithPath:#"$(TARGET_BUILD_DIR)"] pathForResource:#"SimpleTestList" ofType:#"plist"];
STAssertNotNil(path, #"Bundle Location couldn't find the file specified");
Essentially, the assert on path is not successful, but I'm not sure what to put for the path or directory to reference my unitTest bundle that I've told to copy the bundle resources. Calling [NSBundle mainBundle] does not work either.
Ok, so I've figured it out. In order to open a file in a unit test, you'll need to specify the file to open as:
NSString * filePath = [[NSBundle bundleForClass:[self class] ] pathForResource:#"SimpleTestList" ofType:#"plist"];
If you include this in a class that's compiled as part of your unit test bundle, that class will look inside the unit test bundle for the file SimpleTestList.plist.
For a unit test, just make sure you set up "Copy Bundle Resources" to include your plist in your unit test bundle.
If you need the application delegate, you have to run the unit tests on the device itself and not the simulator. Also, you will see unit test output appear in the console, not in the build results.
The key thing to know is that there are two types of unit tests - logic tests that are run outside of the executable, and then integrated system kinds of tests that need the full running environment.
The logic tests MUST be run with the simulator selected as the target or they will not run.
The integrated system tests MUST be run as part of the executable, on the device - you'll want a new target to accomplish this.
Sorry this is all so complex, this aspect is still very much a work in progress compared to many other unit testing frameworks.
The Swift 3 translation of Gary's answer above (using an URL instead of a string path) is:
let url = Bundle(for: type(of: self)).url(forResource: "SimpleTestList", withExtension: "plist")
Notice the critical and non-obvious part type(of: self) instead of [self class].