We have some custom roslyn analyzers for one of our .net project. Some of the rules need to analyze all base classes deep of a given ClassDeclaration. The problem is, that we also need the SematicModel which belongs to the base classes in order to resolve the GetDeclaredSymbol of that ClassDeclaration. Currently we are getting the SemanticModel by resolving it at the SyntaxNodeAnalysisContext.Compilation.
This works when compiling our project from the scratch, but when editing the code roslyn analyzers are also executed periodically.
Sometimes we are getting a System.ArgumentException mentioning the SyntaxTree is not part of the compilation.
Is there a save way to analyze all base classes of a given ClassDeclaration with the need to have the SemanticModel belonging to each base class as well as the SyntaxNode which is currently analysed. Please find the code below which shows how we are analyzing the base class currently.
Does anybody has an idea how to avoid the error mentioned above or what I am doing wrong?
public override void Initialize(AnalysisContext context)
{
context.RegisterCompilationStartAction(compilationContext =>
{
//... here we are collecting some base stuff from the compilationContext.Compilation
compilationContext.RegisterSyntaxNodeAction(syntaxNodeAnalysisContext =>
{
var classDeclaration = (ClassDeclarationSyntax)syntaxNodeAnalysisContext.Node;
var meAndBaseClasses = GetClassDeclarationsDeep(classDeclaration, compilationContext.Compilation);
// now we can analyze the current node because we have infos about all bases classes deep
}, SyntaxKind.ClassDeclaration);
});
}
protected IEnumerable<ClassDeclarationSyntax> GetClassDeclarationsDeep(ClassDeclarationSyntax classDeclaration, Compilation compilation)
{
foreach (var type in classDeclaration.GetMeAndBaseTypes(compilation.GetSemanticModel(classDeclaration.SyntaxTree)))
{
foreach (var partialType in GetClassDeclarations(type, compilation))
{
yield return partialType;
}
}
}
public static IEnumerable<INamedTypeSymbol> GetMeAndBaseTypes(this ClassDeclarationSyntax classDeclaration, SemanticModel semanticModel)
{
return GetMeAndBaseTypes(semanticModel.GetDeclaredSymbol(classDeclaration));
}
protected IEnumerable<ClassDeclarationSyntax> GetClassDeclarations(INamedTypeSymbol classType, Compilation compilation)
{
return classType.DeclaringSyntaxReferences.SelectMany(t => t.SyntaxTree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>()).Where(t => SymbolEqualityComparer.Equals(classType, compilation.GetSemanticModel(t.SyntaxTree).GetDeclaredSymbol(t)));
}
public static IEnumerable<INamedTypeSymbol> GetMeAndBaseTypes(this INamedTypeSymbol type)
{
List<INamedTypeSymbol> types = new List<INamedTypeSymbol>();
while (type != null)
{
types.Add(type);
type = type.BaseType;
}
return types;
}
Related
When I tried to do unit testing for private methods in a Class getting error as private methods are only accessible inside the class. Here I added sample snippet for my class and mocha test. Kindly provide me solution to implement unit test for private methods.
Class Name: Notification.ts
class Notification {
constructor() {}
public validateTempalte() {
return true;
}
private replacePlaceholder() {
return true;
}
}
Unit Test:
import {Notification} from 'Notification';
import * as chai from "chai";
describe("Notification", function(){
describe('#validateTempalte - Validate template', function() {
it('it should return success', function() {
const result = new Notification()
chai.expect(result.validateTempalte()).to.be.equal(true);
});
});
describe('#replacePlaceholder - Replace Placeholder', function() {
it('it should return success', function() {
const result = new Notification()
// As expected getting error "Private is only accessible within class"
chai.expect(result.replacePlaceholder()).to.be.equal(true);
});
});
});
As a workaround, currently, I am changing access specifier of function replacePlaceholder to public. But I don't think its a valid approach.
A possible solution to omit Typescript checks is to access the property dynamically (Not telling wether its good).
myClass['privateProp'] or for methods: myClass['privateMethod']()
Technically, in current versions of TypeScript private methods are only compile-time checked to be private - so you can call them.
class Example {
public publicMethod() {
return 'public';
}
private privateMethod() {
return 'private';
}
}
const example = new Example();
console.log(example.publicMethod()); // 'public'
console.log(example.privateMethod()); // 'private'
I mention this only because you asked how to do it, and that is how you could do it.
Correct Answer
However, that private method must be called by some other method... otherwise it isn't called at all. If you test the behaviour of that other method, you will cover the private method in the context it is used.
If you specifically test private methods, your tests will become tightly coupled to the implementation details (i.e. a good test wouldn't need to be changed if you refactored the implementation).
Disclaimer
If you still test it at the private method level, the compiler might in the future change and make the test fail (i.e. if the compiler made the method "properly" private, or if a future version of ECMAScript added visibility keywords, etc).
In my case, I use the prototype of the object to get access to a private method. It works well and TS does not swear.
For example:
class Example {
private privateMethod() {}
}
describe() {
it('test', () => {
const example = new Example();
const exampleProto = Object.getPrototypeOf(example);
exampleProto.privateMethod();
})
}
If you use a static method then use exampleProto.constructor.privateMethod();.
In HolgerJeromin's comment, the comment issue has a succinct solution that still uses the property syntax.
The solution is to type cast your object / class to any.
Examples:
(<any>myClass).privateMethod();
const value = (<any>myClass).privateValue;
(myClass as any).privateMethod();
const value = (myClass as any).privateValue;
This method satisfies the compiler as well as the VSCode syntax highlighting.
Here are some of my notes from the issue that talks about this
Accessing via a string is more common, although I don't see why it might be more typesafe.
These features are done deliberately, therefore they are helping more than hindering.
There is probably a way to disable this type of feature so people don't copy and paste this code into production. "noImplicitAny": true, might help in the tsconfig.json
Extract out the private function into a separate/stand alone function, but don't export it externally.
This is somewhat semantically correct, since after all — a private function is private and should not be accessed by anyone except the class itself.
My subjective solution: you could define a new testing-only interface that extends the original one by adding the private methods as (implicitly public) interface methods. Then, you cast the instantiated object to this new test type. This satisfies both tsc and VS code type checking. Your example with my solution:
interface INotification {
validateTemplate(): boolean,
}
class Notification implements INotification {
constructor() {}
public validateTemplate() {
return true;
}
private replacePlaceholder() {
return true;
}
}
Testing:
import {Notification} from 'Notification';
import * as chai from "chai";
interface INotificationTest extends INotification {
replacePlaceholder(): boolean;
}
describe("Notification", function(){
describe('#validateTemplate - Validate template', function() {
it('it should return success', function() {
const result = new Notification() as INotificationTest;
chai.expect(result.validateTemplate()).to.be.equal(true);
});
});
describe('#replacePlaceholder - Replace Placeholder', function() {
it('it should return success', function() {
const result = new Notification() as INotificationTest;
// Works!
chai.expect(result.replacePlaceholder()).to.be.equal(true);
});
});
});
Advantages:
tsc and vs code do not complain
IntelliSense (or any other autocomplete) works
simple (subjectively)
If you don't want to define the original interface (INotification), you could just fully define the test one (INotificationTest) instead of extending and cast it in the same manner.
Disadvantages:
Added boilerplate
Need to have both of the interfaces updated and in sync
Potentially introducing bugs by explicitly casting as a non original type.
I leave it up to you to decide whether this is worth it or no. In my case, the positives outweigh the negatives. I have tested this with jest, but I assume that mocha.js is no different here.
Edit: but generally I would agree with Fenton's answer
// module.ts
private async privateMethod = () => "private method executed"
public async testPrivateMethods(...args) {
if (process.env.NODE_ENV === 'development') {
return this.privateMethod(...args);
}
}
Now we can reach our private method to test. In jest file:
// module.spec.js
describe('Module', () => {
let service: Module = new Module();
it('private method should be defined', () => {
expect(service.testPrivateMethods).toBeDefined();
});
}
You need to set your enviroment variable name of NODE_ENV must be development.
// .env
NODE_ENV="development"
The fun thing is that it's just a typescript error (not javascript), so you can fix it with
// #ts-expect-error
and everything works fine.
I consider it as a legitimate solution, as the goal was to suppress typescript in this particular case.
Since private methods are not accessible outside class, you can have another public method which calls replacePlaceholder() in Notification class and then test the public method.
Suppose I have the following classes:
public class Setup { }
public class Configuration<T> where T : class
{
internal Configuration(Setup setup) { }
}
public class Process<T> where T : class
{
internal Process(Configuration<T> configuration) { }
}
I want to register these classes in DryIoc and need each Process<T> to be singleton (as would be Configuration<T>). So, Process<ClassA> would resolve the same instance, and Process<ClassB> will do the same. But Process<ClassA> and Process<ClassB> would be 2 different instances.The same applies to Configuration<T>.How would I register these 3 classes to achieve what I need?Note that constructors are internal.
This is what I've done without success:
var container = new Container();
container.Register<Setup>(Reuse.Singleton);
container.Register(typeof (Configuration<>),
made: Made.Of(typeof (Configuration<>).GetConstructorOrNull(true, typeof (Setup))));
container.Register(typeof(Process<>), Reuse.Singleton,
Made.Of(typeof(Process<>).GetConstructorOrNull(true, typeof(Configuration<>))));
I get: "An exception of type 'System.NullReferenceException' occurred in DryIoc.dll but was not handled in user code" when, as an example I dovar a = container.Resolve<Process<EventArgs>>();
The problem is with getting constructor from generic type. For now you may use DryIoc API to get ConstructorWithResolvableArgumentsIncludingNonPublic:
Working sample looks like that:
var container = new Container();
container.Register<Setup>(Reuse.Singleton);
container.Register(typeof(Configuration<>), Reuse.Singleton,
made: FactoryMethod.ConstructorWithResolvableArgumentsIncludingNonPublic);
container.Register(typeof(Process<>), Reuse.Singleton,
FactoryMethod.ConstructorWithResolvableArgumentsIncludingNonPublic);
var p = container.Resolve<Process<EventArgs>>();
In future versions it will be more simple like FactoryMethod.Constructor(includeNonPublic: true).
Update with workaround:
This is an actual issue in DryIoc 2.9.7 with creating singletons with internal constructor. The fix is on the way. For now you can use a workaround by disabling certain singleton optimizations with rule:
var container = new Container(rules => rules.WithoutEagerCachingSingletonForFasterAccess());
Updated live sample.
Update with fix:
The problem is fixed in DryIoc 2.10
I have a generic class for making and processing JSON API requests. I pass in the TParam and TResult template parameters but when I use a derived type it's implementation is not being called.
Here is some code you can throw in a playground to illustrate:
import Cocoa
// Base class for parameters to POST to service
class APIParams {
func getData() -> Dictionary<String, AnyObject> {
return Dictionary<String, AnyObject>()
}
}
// Base class for parsing a JSON Response
class APIResult {
func parseData(data: AnyObject?) {
}
}
// Derived example for a login service
class DerivedAPIParams: APIParams {
var user = "some#one.com"
var pass = "secret"
// THIS METHOD IS CALLED CORRECTLY
override func getData() -> Dictionary<String, AnyObject> {
return [ "user": user, "pass": pass ]
}
}
// Derived example for parsing a login response
class DerivedAPIResult: APIResult {
var success = false
var token:String? = ""
// THIS METHOD IS NEVER CALLED
override func parseData(data: AnyObject?) {
/*
self.success = data!.valueForKey("success") as Bool
self.token = data!.valueForKey("token") as? String
*/
self.success = true
self.token = "1234"
}
}
class APIOperation<TParams: APIParams, TResult: APIResult> {
var url = "http://localhost:3000"
func request(params: TParams, done: (NSError?, TResult?) -> ()) {
let paramData = params.getData()
// ... snip making a request to website ...
let result = self.parseResult(nil)
done(nil, result)
}
func parseResult(data: AnyObject?) -> TResult {
var result = TResult.self()
// This should call the derived implementation if passed, right?
result.parseData(data)
return result
}
}
let derivedOp = APIOperation<DerivedAPIParams, DerivedAPIResult>()
let params = DerivedAPIParams()
derivedOp.request(params) {(error, result) in
if result? {
result!.success
}
}
The really weird thing is that only the DerivedAPIResult.parseData() is not called, whereas the DerivedAPIParams.getData() method is called. Any ideas why?
UPDATE: This defect is fixed with XCode 6.3 beta1 (Apple Swift version 1.2 (swiftlang-602.0.37.3 clang-602.0.37))
Added info for a workaround when using XCode 6.1 (Swift 1.1)
See these dev forum threads for details:
https://devforums.apple.com/thread/251920?tstart=30
https://devforums.apple.com/message/1058033#1058033
In a very similar code sample I was having the exact same issue. After waiting through beta after beta for a "fix", I did more digging and discovered that I can get the expect results by making the base class init() required.
By way of example, here is Matt Gibson's reduced example "fixed" by adding the proper init() to ApiResult
// Base class for parsing a JSON Response
class APIResult {
// adding required init() to base class yields the expected behavior
required init() {}
}
// Derived example for parsing a login response
class DerivedAPIResult: APIResult {
}
class APIOperation<TResult: APIResult> {
init() {
// EDIT: workaround for xcode 6.1, tricking the compiler to do what we want here
let tResultClass : TResult.Type = TResult.self
var test = tResultClass()
// should be able to just do, but it is broken and acknowledged as such by Apple
// var test = TResult()
println(test.self) // now shows that we get DerivedAPIResult
}
}
// Templated creation creates APIResult
let derivedOp = APIOperation<DerivedAPIResult>()
I do not know why this works. If I get time I will dig deeper, but my best guess is that for some reason having required init is causing different object allocation/construction code to be generated that forces proper set up of the vtable we are hoping for.
Looks possibly surprising, certainly. I've reduced your case to something rather simpler, which might help to figure out what's going on:
// Base class for parsing a JSON Response
class APIResult {
}
// Derived example for parsing a login response
class DerivedAPIResult: APIResult {
}
class APIOperation<TResult: APIResult> {
init() {
var test = TResult()
println(test.self) // Shows that we get APIResult, not DerivedAPIResult
}
}
// Templated creation creates APIResult
let derivedOp = APIOperation<DerivedAPIResult>()
...so it seems that creating a new instance of a templated class with a type constraint gives you an instance of the constraint class, rather than the derived class you use to instantiate the specific template instance.
Now, I'd say that the generics in Swift, looking through the Swift book, would probably prefer you not to create your own instances of derived template constraint classes within the template code, but instead just define places to hold instances that are then passed in. By which I mean that this works:
// Base class for parsing a JSON Response
class APIResult {
}
// Derived example for parsing a login response
class DerivedAPIResult: APIResult {
}
class APIOperation<T: APIResult> {
var instance: T
init(instance: T) {
self.instance = instance
println(instance.self) // As you'd expect, this is a DerivedAPIResult
}
}
let derivedOpWithPassedInstance = APIOperation<DerivedAPIResult>(instance: DerivedAPIResult())
...but I'm not clear whether what you're trying should technically be allowed or not.
My guess is that the way generics are implemented means that there's not enough type information when creating the template to create objects of the derived type from "nothing" within the template—so you'd have to create them in your code, which knows about the derived type it wants to use, and pass them in, to be held by templated constrained types.
parseData needs to be defined as a class func which creates an instance of itself, assigns whatever instance properties, and then returns that instance. Basically, it needs to be a factory method. Calling .self() on the type is just accessing the type as a value, not an instance. I'm surprised you don't get some kind of error calling an instance method on a type.
I am pulling my hair out with this one. I have looked and cannot find a simple, clear example of creating and using a partial stub with Microsoft Moles. Maybe I'm missing somethimg, or have my code architected poorly, but I can't seem to get this to work.
Here's my class (simplified):
public class AccountService : IAccountService {
private readonly webServiceProxy IExternalWebServiceProxy;
public AccountService(IExternalWebServiceProxy webServiceProxy) {
this.webServiceProxy = webServiceProxy;
}
public List<AccountModel> GetAccounts(string customerId) {
var returnList = new List<AccountModel>();
var xmlResponse = webServiceProxy.GetAllCustomerAccounts(customerId);
var accountNodes = xmlResponse.SelectNodes("//AccountNodes");
if (accountNodes != null)
{
foreach (XmlNode node in accountNodes)
{
var account = this.MapAccountFromXml(node);
if (!string.IsNullOrEmpty(account.AccountNumber))
{
returnList.Add(account);
}
}
}
return returnList;
}
public AccountModel MapAccountFromXml(XmlNode node) {
if (!IsValidAccount(node) {
return null;
}
// This performs a lot of XML manipulation getting nodes based on attributes
// and mapping them to the various properties of the AccountModel. It's messy
// and I didn't want it inline with the other code.
return populatedAccountModel;
{
public bool IsValidAccount(XmlNode node)
{
var taxSelectValue = node.SelectSingleNode("//FORMAT/Field[#taxSelect='1']").First().Value;
var accountStatus = // similar to first line in that it gets a single node using a specific XPath
var maturityDate = // similar to first line in that it gets a single node using a specific XPath
var maturityValue = // similar to first line in that it gets a single node using a specific XPath
return taxSelectValue != string.Empty && taxSelectValue != "0" && (accountStatusValue != "CL" || (maturityDate.Year >= DateTime.Now.AddYears(-1).Year));
}
}
What I want to do is test my GetAccounts() method. I can stub out the IExternalWebServiceProxy call and return fake XML, but I have internal calls happening in my service since my GetAccounts() method calls MapAccountFromXml() which in turn calls IsValidAccount().
Perhaps the solution is to not worry about breaking out the long and involved MapAccountFromXml() and IsValidAccount() code and just put them inline into the GetAccount() call, but I would rather leave them broken out for code readability.
I have my Moles assembly created, and know I can create a stub version of my class like this
var stubWebService = SIExternalWebServiceProxy {
GetAllCustomerAccounts = delegate {
return SomeHelper.GetFakeXmlDocument();
}
}
var stubAccountService = new SAccountService() { callsBase = true; }
My problem is I don't know how to then override the internal calls to MapAccountFromXml and IsValidAccount and I don't want my Unit Test to be testing thos methods, I'd like to isolate GetAccounts for the test. I read somewhere the methods need to be virtual to be overriden in a partial stub, but could not find anything that then showed how to create a stub that overrides a few methods while calling the base for the one I want to test.
Peer put me on the right track, thank you.
It turned out that what I was looking for is called Detours in Moles. Rather than stub an interface using
var stubAccountService = new SIAccountService();
what I needed to do was create an instance of my AccountService and then detour all calls to the methods I wanted to mock, like this
var accountService = new AccountService();
MAccountService.AllInstances.MapAccountFromXmlXmlNode = delegate {
return new AccountModel();
};
The MAccountService is provided by Moles when you Mole your assembly. The only missing piece to this is that for this to work you need to add the following attribute to your test method:
[HostType("Moles")]
This worked for me locally, but in the end I had trouble getting TFS to do automated builds
UPDATE
I just stumbled on another way of doing this, while looking at Rhino Mocks. If the methods in the class being mocked are virtual then you can override them in the mock, like this:
var accountService = new SAccountService();
accountService.MapAccountFromXmlXmlNode = delegate
{
return new AccountModel();
}
Now I can call
accountService.GetMemberAccounts();
and when accountService makes its call to MapAccountFromXml it will be caught by the stub and processed as I deem necessary. No messing with HostType and it works like a charm.
To test methods in you class in issolation you do this with moles by making a mole for the IsValidAccount and MapAccountFromXml methods. Or make a stub implementation with stubs where you let the stub call the orriginal methode using base. Or what I think is a nicer solution, make a test class which overrides the methods you do want to stub (this is the same what a stub would do, except you see all what is happening in your own code):
public class TestHelperAccountService : AccountService {
public override AccountModel MapAccountFromXml(XmlNode node) {
return new AccountModel(){
//Accountmodelstub
};
{
public override bool IsValidAccount(XmlNode node)
{
return true;
}
}
This way you can do your test for the GetAccount method on your TestHelperAccountService class where you GetAccount method runs in full issolation. You can do the same for the methods like MapAccountFromXml to test them seperatly.
I have two test fixtures that have a common parent. Although the tests involve SQLite/NHib type of stuff, which are usually a bit of a at first, there is something I don't understand about NUnit that I'm hoping will help be fix these tests.
The good news is that if I run (via TestDriven.Net) both the subclassed TestFixtures without selecting the common parent, all tests succeed. But if I include the common parent in the run, I get failures (presumably because my NHib session has been disposed or lost it's binding).
Can anyone explain why the two tests succeed on their own but not with
the parent, and if there is someway to enforce the successful
behavior?
Cheers,
Berryl
public class ActivityTestFixture : GreenQueryOnlySQLiteTestFixture
{
protected IProjectDao _projectDao;
protected IDao<Account> _accountDao;
protected override void OnFixtureSetUp()
{
base.OnFixtureSetUp();
_projectDao = DataFactory.GetProjectDao(_sessionFactoryContext.SessionFactory);
_accountDao = DataFactory.GetAccountDao(_sessionFactoryContext.SessionFactory);
}
}
[TestFixture]
public class AccountDaoTests : ActivityTestFixture
{
[Test]
public void FindAll_IsEquivalentToSeeds() {
IList<Account> found;
using (var tx = _session.BeginTransaction()) {
found = _accountDao.FindAll();
tx.Commit();
}
found.AssertUnsavedValueSequenceEqual(ActivitySubjectSeeds.AllAccounts.ToAr ray());
}
}
[TestFixture]
public class ProjectDaoTests : ActivityTestFixture
{
[Test]
public void FindAll_IsEquivalentToSeeds()
{
IList<Project> found;
using (var tx = _session.BeginTransaction())
{
found = _projectDao.FindAll();
tx.Commit();
}
found.AssertUnsavedValueSequenceEqual(ActivitySubjectSeeds.Projects.ToArray ());
}
}
Not sure what the error that you're getting is, but it's likely because you have some kind of static fields in the GreenQueryOnlySQLiteTestFixture class. The way NUnit works is that a fixture lives for the lifetime of the tests inside of it. So it is only created once for all of the tests. This is different from xUnit which lives for the lifetime of one test.
Without seeing the entire implementation it's hard to see what is wrong. However, you can remove the TestFixtureAttribute from your parent fixture since it does not appear to have any tests anyway.