Probably not a good title, and this question might be stupid, but I really have no idea how to do this.
I've created a project that connects to a DB with EF Core . I've created my DbContext class and my Repository class that does the actual querying .
Then I created another class , maybe I created it wrong, but I made it similar to a controller of an MVC project . This is my class:
public class ExtractCustomersToBeMarked
{
private ICampaignRepository _repository;
private ILogger<ExtractCustomersToBeMarked> _logger;
public ExtractCustomersToBeMarked(ILogger<ExtractCustomersToBeMarked> logger, ICampaignRepository repository)
{
_repository = repository;
_logger = logger;
}
public async Task ExtractCustomers()
{
IEnumerable<CampaignKnownCustomers> result = _repository.getCustomersGUID();
... I want to debug this code
}
}
Now I want to debug my program . I tried calling the method from my Main program , but with no success as I don't know what to pass to the constructor (MVC does that on its own) . That's what I tried :
public static void Main(string[] args)
{
var p = new Program();
p.Run().Wait();
}
private async Task Run()
{
ExtractCustomersToBeMarked ectm = new ExtractCustomersToBeMarked(?,?);
await ExtractCustomersToBeMarked.ExtractCustomers();
}
I know it doesn't look good, this structure is simply for debugging . If theres another way I'm open to hear about it..
How can I hit the debugger on ExtractCustomers?
I guess you have implemented a CampaignRepository class. Provided that you want to use this implementation when debugging the ExtractCustomers() method, you should simply create an instance of it and pass to the method:
static void Main(string[] args)
{
ExtractCustomersToBeMarked ectm = new ExtractCustomersToBeMarked(null, new CampaignRepository());
ectm.ExtractCustomers().Wait();
}
The same goes for the logger. Create an instance of a class that implements the ILogger<ExtractCustomersToBeMarked> if you use the logger in the method that you want to debug. Don't forget to pass it to the constructor of the ExtractCustomersToBeMarked class when you create an instance of it.
You may want to implement an integration test instead of modifying the Main() method of the application itself though but that's another story.
Summary I'd suggest writing Unit Tests against the code you want to debug.
Detail When you have Unit Tests in place you can run each individual test under Debug, allowing you to step through the code exactly like you do when debugging the application; but with the benefit that you get to define the scope and context of the test, for example you can test isolated parts of your system independently of others.
Once a test is in place, it can shorten the time taken by the code+debug iteration cycle, making you more productive. It achieves that because the test fires you straight into the relevant code with the test scenario already set up, rather than the whole application having to start up, and you navigating through to the relevant parts each time to get into the scenario you want.
Another benefit of these tests (if they are written the right way) is that you can make them run as part of an automated build which is triggered whenever someone changes some code. This means that if anyone breaks that code, the test will fail, and the build will fail.
Related
I'm trying to evaluate a workflow library for a project I'm working on. The lib can be found at github workflow-core.
To start things up I was trying to build a simple workflow, that just writes some text to a file. The curious thing is, that the workflow works fine, when called from a console application project. But when I use the same code in an NUnit test and run it, it doesn't write anything to the file.
I'm a little lost here and don't even know which details are import for you guys to know to help me figure this out, but maybe this might be relevant?
The workflow-core library is build on .NET standard 2.0
The NUnit project and the console project both use .NET Framework 4.7.2
The workflow-core lib uses all kinds of Tasks (as in Task Parallel Library) stuff
The workflow-core lib is build with dependency injection using the Microsoft.Extensions.DependencyInjection library
And here is the relevant code:
First the workflow class:
public class HelloWorldWorkflow : IWorkflow
{
public string Id => nameof(HelloWorldWorkflow);
public int Version => 1;
public void Build(IWorkflowBuilder<object> builder)
{
builder.StartWith((context) =>
{
File.WriteAllText(#"C:\Test\test.txt", "Test line worked!");
return ExecutionResult.Next();
});
}
}
The calling code from the console app (working):
class Program
{
static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging((config) => config.AddConsole());
serviceCollection.AddWorkflow();
serviceCollection.AddTransient<LogStep>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var host = serviceProvider.GetService<IWorkflowHost>();
host.RegisterWorkflow<HelloWorldWorkflow>();
host.Start();
host.StartWorkflow(nameof(HelloWorldWorkflow));
Console.WriteLine("Done");
Console.ReadLine();
host.Stop();
}
}
And the code from my test project (not working):
[TestFixture]
public class ExplorationTests
{
private ServiceProvider _serviceProvider;
private IWorkflowHost _host;
[OneTimeSetUp]
public void Init()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging((config) => config.AddConsole());
serviceCollection.AddWorkflow();
serviceCollection.AddTransient<LogStep>();
serviceCollection.AddTransient<HelloWorldWorkflow>();
_serviceProvider = serviceCollection.BuildServiceProvider();
_host = _serviceProvider.GetService<IWorkflowHost>();
_host.RegisterWorkflow<HelloWorldWorkflow>();
_host.Start();
}
[Test]
public void Test()
{
_host.StartWorkflow(nameof(HelloWorldWorkflow));
}
[OneTimeTearDown]
public void TearDown()
{
_host.Stop();
}
}
I'd be glad for any clues on how to figure this out.
Execution of workflows is asynchronous, therefore you have to wait for some kind of event to occur which signals the completion.
Otherwise your test teardown will kill the host before the workflow has the chance to do anything.
This answer's first version contained:
Adding .Wait() or one of its overloadings (which allow to specify a maximum duration to wait) to the result of StartWorkflow to block the test until the workflow has completed.
Unfortunately that's wrong as StartWorkflow returns a Task yielding only the ID of the workflow instance. When this task is resolved your workflow probably hasn't done anything meaningful.
There is a feature request on GitHub asking for the desired feature: Wait for workflow to finish
Until that request is resolved, you may help yourself by creating a ManualResetEvent or maybe AutoResetEvent and putting it somewhere your final workflow step can access and call .Set() on it. Your test should wait for that by calling .WaitOne() on it (this is blocking).
Another event which might be sufficient (but inefficient) is just having waited a long enough duration: Thread.Sleep(2000) waits two seconds. Please be aware that even after that it's possible that your workflow has not completed due to the asynchronous nature of the workflow executor.
Can you try by making 'var serviceCollection' as class member of ExplorationTests. Otherwise code looks ok.
It looks like your test starts a task running in the host and then exits without waiting for completion. The one time teardown would then run immediately and stop the host.
You should not be ending the test without waiting for the task to complete.
I was wondering if it was possible to have a start-up script before running any load tests? For example, perhaps to seed some data or clear anything down prior to the tests executing.
In my instance I have a mixed bag of designer and coded tests. Put it simply, I have:
Two coded tests
A designer created web test which points to these coded tests
A load test which runs the designer
I have tried adding a class and decorating with the attributes [TestInitialize()], [ClassInitialize()] but this code doesn't seem to get run.
Some basic code to show this in practice (see below). Is there a way of doing this whereby I can have something run only the once before test run?
[TestClass]
public class Setup : WebTest
{
[TestInitialize()]
public static void Hello()
{
// Run some code
}
public override IEnumerator<WebTestRequest> GetRequestEnumerator()
{
return null;
}
}
Probably should also mention that on my coded tests I have added these attributes and they get ignored. I have come across a workaround which is to create a Plugin.
EDIT
Having done a little more browsing around I found this article on SO which shows how to implement a LoadTestPlugin.
Visual Studio provides a way of running a script before and also after a test run. They are intended for use in deploying data for a test and cleaning up after a test. The scripts are specified on the "Setup and cleanup" page in the ".testsettings" file.
A load test plugin can contain code to run before and after any test cases are executed, also at various stages during test execution. The interface is that events are raised at various points during the execution of a load test. User code can be called when these events occur. The LoadTestStarting event is raised before any test cases run. See here for more info.
If you are willing to use NUnit you have SetUp/TearDown for a per test scope and TestFixtureSetUp/TestFixtureTearDown to do something similar for a class (TestFixture)
Maybe a bit of a hack, but you can place your code inside the static constructor of your test class as it will automatically run exactly once before the first instance is created or any static members are referenced:
[TestClass]
public class Setup : WebTest
{
static Setup()
{
// prepare data for test
}
public override IEnumerator<WebTestRequest> GetRequestEnumerator()
{
return null;
}
}
I have a number of 'unit tests' (they're really integration tests) in several classes that access a shared resource, and I want each test class to only acquire the resource once (for performance reasons).
However, I'm getting issues when I release the resource in [ClassCleanup], because that isn't running until all tests are completed.
Here's a simplified example:
using Microsoft.VisualStudio.TestTools.UnitTesting;
static class State
{
public static string Thing;
}
[TestClass]
public class ClassA
{
[ClassInitialize]
public static void Initialize(TestContext ctx)
{
State.Thing = "Hello, World!";
}
[ClassCleanup]
public static void Cleanup()
{
State.Thing = null;
}
[TestMethod]
public void TestA()
{
Assert.IsNotNull(State.Thing); // Verify we have a good state
}
}
[TestClass]
public class ClassB
{
[TestMethod]
public void TestB()
{
Assert.IsNull(State.Thing); // Verify we have an uninitialized state
// Initialize state, do stuff with it
}
}
On my machine at least, TestB fails because it runs before ClassA has been cleaned up.
I read ClassCleanup May Run Later Than You Think, but that doesn't explain any way to change the behaviour. And I realize I shouldn't depend on test ordering, but it's too expensive to re-acquire the resource for every test, so I want to group them by class.
How can I fix this? Is there a way to force each test class to run as a unit, and make the cleanup occur immediately?
Although ClassCleanup might be unreliable in terms of when it is run, ClassInitialize is not; why not give each testclass that relies on this shared resource a ClassInitialize that cleans up the shared resource of the previous test class (if any), right before acquiring the resource itself?
The only time the shared resource isn't released is for the last test class, but you could handle that with the ClassCleanup because then it doesn't matter anymore when it is run (since there won't be any more test classes following it).
Is there any reason that you cannot make this resource shared by the entire assembly all at once? Make it an internal or public static variable in one of the test classes (or a separate designated class), and refer to it directly from all the test classes. The initialization of the resource will take place in the [AssemblyInitialize] method and the cleanup will take place at the [AssemblyCleanup].
I am using Approval Tests. On my dev machine I am happy with DiffReporter that starts TortoiseDiff when my test results differ from approved:
[UseReporter(typeof (DiffReporter))]
public class MyApprovalTests
{ ... }
However when the same tests are running on Teamcity and results are different tests fail with the following error:
System.Exception : Unable to launch: tortoisemerge.exe with arguments ...
Error Message: The system cannot find the file specified
---- System.ComponentModel.Win32Exception : The system cannot find the file
specified
Obviously it cannot find tortoisemerge.exe and that is fine because it is not installed on build agent. But what if it gets installed? Then for each fail another instance of tortoisemerge.exe will start and nobody will close it. Eventually tons of tortoisemerge.exe instances will kill our servers :)
So the question is -- how tests should be decorated to run Tortoise Diff on local machine
and just report errors on build server? I am aware of #IF DEBUG [UseReporter(typeof (DiffReporter))] but would prefer another solution if possible.
There are a couple of solutions to the question of Reporters and CI. I will list them all, then point to a better solution, which is not quite enabled yet.
Use the AppConfigReporter. This allows you to set the reporter in your AppConfig, and you can use the QuietReporter for CI.
There is a video here, along with many other reporters. The AppConfigReporter appears at 6:00.
This has the advantage of separate configs, and you can decorate at the assembly level, but has the disadvantage of if you override at the class/method level, you still have the issue.
Create your own (2) reporters. It is worth noting that if you use a reporter, it will get called, regardless as to if it is working in the environment. IEnvironmentAwareReporter allows for composite reporters, but will not prevent a direct call to the reporter.
Most likely you will need 2 reporters, one which does nothing (like a quiet reporter) but only works on your CI server, or when called by TeamCity. Will call it the TeamCity Reporter. And One, which is a multiReporter which Calls teamCity if it is working, otherwise defers to .
Use a FrontLoadedReporter (not quite ready). This is how ApprovalTests currently uses NCrunch. It does the above method in front of whatever is loaded in your UseReporter attribute. I have been meaning to add an assembly level attribute for configuring this, but haven't yet (sorry) I will try to add this very soon.
Hope this helps.
Llewellyn
I recently came into this problem myself.
Borrowing from xunit and how they deal with TeamCity logging I came up with a TeamCity Reporter based on the NCrunch Reporter.
public class TeamCityReporter : IEnvironmentAwareReporter, IApprovalFailureReporter
{
public static readonly TeamCityReporter INSTANCE = new TeamCityReporter();
public void Report(string approved, string received) { }
public bool IsWorkingInThisEnvironment(string forFile)
{
return Environment.GetEnvironmentVariable("TEAMCITY_PROJECT_NAME") != null;
}
}
And so I could combine it with the NCrunch reporter:
public class TeamCityOrNCrunchReporter : FirstWorkingReporter
{
public static readonly TeamCityOrNCrunchReporter INSTANCE =
new TeamCityOrNCrunchReporter();
public TeamCityOrNCrunchReporter()
: base(NCrunchReporter.INSTANCE,
TeamCityReporter.INSTANCE) { }
}
[assembly: FrontLoadedReporter(typeof(TeamCityOrNCrunchReporter))]
I just came up with one small idea.
You can implement your own reporter, let's call it DebugReporter
public class DebugReporter<T> : IEnvironmentAwareReporter where T : IApprovalFailureReporter, new()
{
private readonly T _reporter;
public static readonly DebugReporter<T> INSTANCE = new DebugReporter<T>();
public DebugReporter()
{
_reporter = new T();
}
public void Report(string approved, string received)
{
if (IsWorkingInThisEnvironment())
{
_reporter.Report(approved, received);
}
}
public bool IsWorkingInThisEnvironment()
{
#if DEBUG
return true;
#else
return false;
#endif
}
}
Example of usage,
[UseReporter(typeof(DebugReporter<FileLauncherReporter>))]
public class SomeTests
{
[Test]
public void test()
{
Approvals.Verify("Hello");
}
}
If test is faling, it still would be red - but reporter would not came up.
The IEnvironmentAwareReporter is specially defined for that, but unfortunatelly whatever I return there, it still calls Report() method. So, I put the IsWorkingInThisEnvironment() call inside, which is a little hackish, but works :)
Hope that Llywelyn can explain why it acts like that. (bug?)
I'm using CC.NET and I do have TortoiseSVN installed on the server.
I reconfigured my build server to allow the CC.NET service to interact with the desktop. When I did that, TortiseMerge launched. So I think what's happening is that Approvals tries to launch the tool, but it cant because CC.NET is running as a service and the operating system prevents that behavior by default. If TeamCity runs as a service, you should be fine, but you might want to test.
I'm wondering what is the best way to initialize log4Net in a NUnit project. Of course I want to call the init code (ie. XmlConfigurator.Configure()) as soon as I can to get as many early log output as I can. But since my project is run through NUnit, I have little control on its entry point.
According to NUnit documentation, it should call some constructors first, then a method marked with the [SetUp] attribute in a class marked with [TestFixtureSetup].
So, First, I created a static helper class which I can call several times without trouble.
public static class LoggingFacility
{
private static bool _loggerIsUp = false;
public static void InitLogger()
{
if (_loggerIsUp == false)
XmlConfigurator.ConfigureAndWatch(f);
_loggerIsUp = true;
}
}
Then, I made all my [TestFixtureSetup] inherit a single one that does pretty much nothing else than calling LoggingFacility.initLogger(). But that still leaves all constructors that are run earlier, in an order I can only assume random. And moreover, it will probably do some static initializations before I am even able to execute some code.
In fact, as I can see in my log, the first 4 seconds or so of execution are completely unrecorded.
Does it mean I will have to call my InitLogger() in every constructor and forbid the use of any static initializer? That's tough job!
Does somebody know a magic trick with this?
For single initialization point you should use class marked with [SetUpFixture] attribute and method marked with [SetUp], for example:
[SetUpFixture]
public class TestsInitializer
{
[SetUp]
public void InitializeLogger()
{
LoggingFacility.InitLogger();
}
}
Now, this method ([SetUp] InitializeLogger) will run before any test is run, same as one marked with [TearDown] will run once all tests are run. But here's the catch - what does any and all mean in this context? Tests from classes declared in the same namespace as class marked with [SetUpFixture].
For example, assuming hierarchy like this:
- Tests
--- Business
----- TestsInitializer.cs // SetUpFixture class
----- FirstBusinessTests.cs
----- SecondBusinesTests.cs
--- ComplexLogic
----- VeryComplexLogicTests.cs
First and SecondBusinessTests will run after SetUp from TestsInitializer, however VeryComplexLogicTests might run in random order.
According to linked documentation, if you declare SetUpFixture class outside of any namespace, setup and teardown will apply for entire assembly:
Only one SetUpFixture should be created in a given namespace. A SetUpFixture outside of any namespace provides SetUp and TearDown for the entire assembly.
A work mate provided me with the following workaround, that does the job:
In all my classes that require logging, I had the following logger initialization
private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
I simply changed it to a singleton initializer
private static readonly ILog Log = LoggingFacility.GetLoggerWithInit(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
/*** ... ***/
public static class LoggingFacility
{
private static bool _loggerIsUp = false;
public static ILog GetLoggerWithInit(Type declaringType)
{
if (_loggerIsUp == false)
XmlConfigurator.Configure(_log4NetCfgFile);
_loggerIsUp = true;
return LogManager.GetLogger(declaringType);
}
}
Because I have this code in every class, this static initializer has to be called very early by NUnit wile instantiating my test classes.
Next step is to make that thread safe :(