How to access TestContext in Specflow 3.0 [BeforeTestRun] static Hook - testing

I have started using Specflow 3.0 for .NET core tests project with built-in MSTest runner.
I encountered problem while trying to setup one-time method execution in order to persist bearer token value for all running tests in Specflow.
So my idea was to create [BeforeTestRun] Hook static method which would make HTTP request with given credentials. The problem is that those credentials are stored in .runsettings file, so I need to have MSTest's TestContext object in order to access dictionary property.
In Scenario's I'm injecting TestContext and it works fine, however I do not know how to access this object in static [BeforeTestRun] method. Is there any chance to create this object myself and store in static property?
As you see this is abstract class, so I guess Test Framework is automatically injecting concrete implementation in Scanarios with DI. How could I get this concrete implementation?
If solution is not present, would you suggest another approach how could I store configurable settings besides .runsettings so I could access them in static [BeforeTestRun] method without DI?
Thank you

AFAIK I know the behaviour of TestContext in MSTest, you get in plain MSTest for every test your own instance of TestContext.
So you can't get an instance for the whole testrun.
What you could do is, that you do the HTTP request in the BeforeScenario hook of the first scenario that gets executed. There you can get to the TestContext instance without problems.

Related

Can I create an object from the DI container/Lamar in .NET 6.0 minimal hosting, preserving singletons?

We have migrated from a windows Framework 4.7 application to .NET 6.0. Lamar is added for Dependency Injection. We are trying to finalize a refactor to the latest "one-file" program.cs but are getting unexpected System.ObjectDisposedException: 'Cannot access a disposed object'. In all cases, the error is against a Func<T> during object creation.
All our tests are running correctly using the same environment, except to start the tests we (a) create the DI container and (b) use the container to create an object that loads the singletons (from MongoDB):
Container = new Container(registry);
var start = Container.GetInstance<HomeService>();
In the program.cs, we configure the container, but do not get to see it created, or access it inside program.cs. Instead we create HomeService from IServiceProvider during the first use of a controller. Here we were trying to limit the lifecyle scope during creation:
using (var scope = _container.CreateScope())
{
scope.ServiceProvider.GetService<INewHomeService>();
}
For test, we use the same loading steps, except for adding controllers/mvc, of course (i.e. NOT using builder.Services.AddControllers(); and builder.Services.AddMvc() for (integration) testing).
We have tried a lot of different things, like creating our object independently to the startup, but that did not align the singletons. We can get functionality by using static instead, but then we lose dynamic change access.
Some great tips like Resolving instances with ASP.NET Core DI from within ConfigureServices and https://andrewlock.net/exploring-dotnet-6-part-10-new-dependency-injection-features-in-dotnet-6/ but I can't see the specific example to get the live container just after initial creation.
Is it possible that the issue is just the difference between the lifecycle management of the new .NET DI implementation? As this is configuration at the composition root, if we can configure as per our testing approach, it should solve our problem. Other solutions welcome!
The problem 'Cannot access a disposed object' was being caused by a lifecycle mismatch between retained context and the controller access. The code retained a handle on the state object, that had a handle on the factory using FUNC. As we did not configure the Func as anything, it was transient during the controller graph creation, and so was disposed when the controller request ended.
To solve, we tried registering ALL of the FUNC, per How to use Func<T> in built-in dependency injection which was a large task as we had a few factories throughout an old codebase.
The better solution was to create a factory in the composition root, and use an injected IserviceProvider (or with Lamar an IContainer). This is a simple workaround.
With our creation concern, the creation of our object after the completion of the startup process is working correctly as a lazy validation of the first controller access.

Using Byte Buddy to expand Spring Boot's classpath

The AWS SDK can locate API call interceptors via classpath scanning (looking for software/amazon/awssdk/global/handlers/execution.interceptors and instantiating classes specified there).
I'm writing a Java Agent with the intention of causing my interceptors to be locatable by the AWS SDK.
My interceptor is bundled with the Java Agent.
My interceptor implements AWS's ExecutionInterceptor.
The AWS SDK is not bundled with my agent, because I'd like the end-user to provide their own AWS SDK version.
For regular standalone applications, this is a no-brainer, as the Java Agent is automatically added to the runtime classpath of the application. The AWS SDK finds my interceptors with no problem.
However, this approach completely breaks with Spring Boot applications where the AWS SDK is bundled as a dependency under BOOT-INF/lib. The reason boils down to Spring Boot's classloading hierarchy. My interceptor class can be found, but its loading fails due to inability to find AWS's ExecutionInterceptor, as it is loaded in a "lower" classloader in the hierarchy.
So I figured that my approach should be to somehow modify Spring Boot's classloader search. However, I'm facing these issues:
At the time of the agent being called, Spring Boot's "lower" classloader isn't created yet.
I am not entirely sure what it is that I need to instrument.
I've read of Byte Buddy being able to help in such "interesting" circumstances but haven't found a way to make this work yet. Any ideas?
(EDIT: I'm looking for a solution that doesn't require code/packaging changes, hence the Java Agent approach)
(EDIT: Things I've tried)
Following Rafael's answer: The method in the SDK that resolves all interceptors is in the class SdkDefaultClientBuilder, and is called resolveExecutionInterceptors.
The following, then, works for standalone JARs which are not SpringBoot applications:
public static void installAgent(Instrumentation inst) {
new AgentBuilder.Default()
.with(RedefinitionStrategy.DISABLED)
.type(ElementMatchers.nameEndsWith("SdkDefaultClientBuilder"))
.transform(
new Transformer() {
#Override
public Builder<?> transform(Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) {
return builder.visit(Advice.to(MyAdvice.class).on(ElementMatchers.named("resolveExecutionInterceptors")));
}
}
).installOn(inst);
}
For SpringBoot applications, however, it looks like the advice isn't applied at all. I am guessing that this is because the SdkDefaultClientBuilder type isn't even available at the time when the agent starts. It is available during SpringBoot's runtime, in a different classloader.
Byte Buddy allows you to inject code in any method of any class, so the first and only major thing you would need to find out would be where your interceptor is instantiated. This can typically be done by setting a breakpoint in the constructor of the interceptor in the working scenario and investigating the methods in the stack. Find out where the classes are discovered, for example the method where software/amazon/awssdk/global/handlers/execution.interceptors is read.
Once you have identified this method, you would need to find a way to manually extract the interceptors defined by your agent and to manually add them. For example, if the file-extracted interceptors are added to an argument of type List<Interceptor>, you could use Byte Buddy to modify this method to also add those of your agent.
Normally, you use Byte Buddy's AgentBuilder in conjunction with Advice to do so. Advice let's you inline code into another method as for example, assuming you find a method with an argument of type List<Interceptor>:
class MyAdvice {
#Advice.OnMethodEnter
static void enter(#Advice.Argument(0) List<Interceptor> interceptors) {
interceptors.addAll(MyAgent.loadMyInterceptors());
}
}
You can now inline this code into the method in question by:
class MyAgent {
public static void premain(String arg, Instrumentation inst) {
new AgentBuilder.Default().type(...).transform((builder, ...) -> builder
.visit(Advice.to(MyAdvice.class).on(...))).install(inst);
}
}
You might need to use AgentBuilder.Transformer.ForAdvice if the classes in question are not available on the agent's class loader where Byte Buddy resolves the advice using both the target and the agent class loader.

NSubstitute mocking a NLog logger fails

I have a test that looks like following:
[Test]
public void LoggerTest()
{
var log = Substitute.For<Logger>();
log.DidNotReceiveWithAnyArgs().Info("");
log.ReceivedWithAnyArgs().Info("");
}
The test succeeds, which it obviously shouldn't. To my best knowledge this is the syntax according to the NSubstitue website.
Can anybody tell me where the problem lies?
I use NSubstitue in version 1.7.2.0 from the NuGet package manager.
NLog.Logger is a concrete class with non-virtual members, so NSubstitute will not be able work with it (see the note on Creating a substitute).
If you need to test logging one option is to wrap the log functionality in your own, app-specific interface. This makes it easier to substitute in a new logger for testing purposes (can use NSubstitute or other mocking library, or hand-code your own TestLogger tailored for your test purposes).

testing custom ASP.NET membership provider

I'm using custom asp.net membership provider with underlaying nhibernate data access code, which is fine. Now I need to exercise these methods using tests.
Anyone interested in suggesting how these methods should be tested? with providing some links explaining test methods using some standars maybe ?
This is my first question so be gentle :)
When it comes to unit testing any code that does something with the database or a 3rd party library you should de-couple these dependencies so that your tests only test your code.
For example, if we have a method in our membership provider for adding a single user, what we want to be testing is that our code for this single method works correctly and not that the database is up and running or that methods called by this method work. Our unit test should still pass even if the database is offline or if method calls on other classes fail.
This is where Mocking comes into play. You'll want to mock out your data context and set up any methods you'll be using on it so that you can control its response.
Look closely at the methods you have in your membership provider. What should each one do? That's the only thing you really want to test. Does this method, as a standalone unit, do the job I'm expecting it to.
Membership providers are pretty difficult to mock and test, so personally I don't bother. What I do however is place all my membership code in classes that are easily testable.
Most of my custom providers look something like this:
public class CustomMembershipProvider : MembershipProvider
{
private readonly IUserService _userService;
public ButlinsMembershipProvider()
{
_userService = DI.Resolve<IUserService>();
}
public override bool ValidateUser(string username, string password)
{
return _userService.Authenticate(username, password);
}
}
In this example, I would write integration tests to verify the behavior of the user service. I don't test the provider.

NHibernate Passing Session to the Repository

How would I go about passing a session to a repository class?
Let's say that the I have two projects.
1) TestSuite
2) BusinessObjects
The repository is contained in the BusinessObjects project. The NHibernate session is opened in the TestSuite project. Now, I want to use the same session since the TestSuite project starts a transaction on that session. Currently, I am using the following:
var repository = new CustomerRepository(_session);
Of course, this looks ugly! I am thinking somehow a dependency injection framework can be hooked and provide me with the ISession object without having to pass into the repository.
In our WCF Service we actually use a UnitOfWork which wraps a single operation and stores the ISession for that operation.
The repositories know how to get an ISession from the current unit of work they are running under.
In terms of testing we have a base test class that any test class which contains tests that touch the database inherits from. We then control the starting and ending of a unit of work in the testfixturesetup. Has worked fairly well for us once you get use to the fact that in the version of NUnit we use teardown is NOT guaranteed to run (in case of an unhandled exception during setup or the test).