This invention relates to systems and methods for calling types.
Many software products sold today are written in managed code. With managed code, such as Microsoft's®.net™ product, as well as other non-Microsoft® products such as Java™, a software product can be made up of a hierarchical arrangement of software objects. One of the advantages of creating a software product with objects is that often each of the objects can be individually tested. This aids developers of the software product by enabling them to test objects, or “units”, of the software product, which is often simpler than testing the whole software product.
A software product written in the “.net” managed code, for instance, can have definitions, such as “classes.” These classes can contain members, such as “methods,” “data components,” and “events.” Each of these classes can be public or non-public. If the class is public, the class members often can easily be called by other software, such as testing software. Referring to
The testing assembly can send information to the universal testing framework based on the output received. This information can include a determination that second method 106 passed or failed, and other information about how the second method performed. The universal testing framework can present this information to a developer in an easy-to-analyze format.
Testing objects with non-public types, however, is often more difficult. It is more difficult because unit testing programs often cannot test objects with non-public types by calling them directly.
To partially address this problem, an object having a non-public type can be tested by writing testing code directly into the production assembly 100. This partial solution, while it allows access to—and thus testing of—objects of non-public types, has various problems. First, in many cases developers want to keep this testing code confidential. If the testing code is written in the production assembly, it can be read by a user that later buys the software program. Second, the testing code wastes a user's computer memory; it takes up memory that is not needed by a user who purchases the software product. Third, the testing code can confuse users and developers when included within the software product.
Another partial solution to this problem is to create a specialized non-production assembly of that part of the software program having the object of the non-public type to be tested. This partial solution, however, is often not sufficiently reliable because it may behave differently than an actual production assembly.
Systems and/or methods are disclosed that are capable of enabling members of a non-public type to be called by calling members of a public type.
The same numbers are used throughout the disclosure and figures to reference like components and features.
Overview
Systems and/or methods (“tools”) are described that enable an object having a non-public type in an assembly of managed code to be called as if the object's type is public. In one embodiment, for instance, the tools generate a public proxy with associated code that is capable of calling members of a non-public type. This public proxy and its associated code can be automatically generated by the tools using reflections from a production assembly having the non-public type.
By calling members of this public proxy, a software application can call the public proxy's corresponding members of a non-public type as if the non-public type is public. This enables a developer to more easily write software applications that need to call objects having non-public types. In one embodiment, the tools enable unit testing of an object having a non-public type as if the object instead has a public type.
Exemplary Proxy Generator and Assemblies
Referring to
In this exemplary architecture, production assembly 202 is a compiled assembly of a software product written at least in part using managed code. This managed code can comprise .net™, Java™, and other languages that enable object-oriented programming and metadata. The production assembly is arranged hierarchically, having objects representing operations and/or code portions of the software product. The production assembly can have public or non-public types. The production assembly contains reflections 210 (also called “metadata”) and managed code 212. The reflections contain information about managed code 212 in the production assembly, such as class, method, and attribute definitions. The reflections can be used by the proxy generator to create the proxy assembly, which is explored in more detail below.
The production assembly is shown having numerous public or non-public types. In this example, the production assembly comprises: a first class 214 that is public containing a first method 216 with arguments having a public type and a first property 218 having a non-public type; a second class 220 that is a non-public type and containing a first field 222 having a non-public type, a second method 224 with arguments having a non-public type, and a first constructor 226 with arguments having a non-public type; a first structure (a.k.a., a “struct” in .net™) 228 that is non-public containing a third method 230 with arguments having a non-public type and a first indexer 232 having a non-public type; and a first enumerator (a.k.a., an “enum” in .net™) 234 that is public containing a first value 236.
Also in this exemplary architecture, proxy generator 204 comprises one or more computer-readable media that is capable of receiving or accessing a non-public type of a production assembly and creating a public proxy and associated code capable of calling that non-public type.
Communication between the components of the architecture is shown with dashed lines. Dotted lines indicate constituent parts of the production assembly. The solid line from the proxy generator to the proxy assembly shows generation by the proxy generator of the proxy assembly.
Generating a Public Proxy
Referring to
In process 300, proxy generator 204 enables an object having a non-public type to be called as if the object's type is public by generating a public proxy with associated code capable of calling members of the non-public type. This associated code can be effective to translate calls made to members of the public proxy into calls to the corresponding members of the non-public type. In the ongoing embodiment, the proxy generator automatically generates the public proxy and associated code, though in other embodiments human interaction can also be used.
Also in this process, components of architecture 200 are used as examples, such as production assembly 202. To aid the reader in understanding one way in which the proxy generator can generate public proxies and associated code, the production assembly comprises types written in .net™. Thus, while this production assembly contains types named “class,” “struct,” and “enum”, other names and types, like “structure” and “enumerator”, Java™ types, and the like can be handled by the proxy generator.
At block 302, proxy generator 204 receives or finds a non-public type. In one embodiment, the proxy generator accesses public and non-public types of an assembly and determines which are public and which are non-public. The proxy generator can, for instance, iteratively scan and pick out the following members of non-public types in production assembly 202: first property 218; second class 220; first field 222; second method 224; first constructor 226; first structure 228; third method 230; first indexer 232; and first value 236.
At block 304, the proxy generator associates an identifier with a particular non-public type. This identifier can comprise a public proxy that has members, which when called, can cause an operation to be initiated that calls members of the non-public type. The public proxy can comprise a namespace of the non-public type, which aids a developer in relating a public proxy to its non-public type.
In the ongoing embodiment, the proxy generator associates a namespace, for example “namespaceMicrosoft.ProxyTypes”, with the original namespace of the non-public type. Thus, if the original namespace for second method 224, for example, is “firstnamespace” the proxy generator can generate a new namespace of “namespaceMicrosoft.ProxyTypes.firstnamespace”. This new namespace can be used for proxy types.
At block 306, the proxy generator generates code that is callable with the public identifier and capable of calling members of a non-public type. In so doing, the code can translate calls made to the public identifier into calls to the members of the non-public type. To generate this code, the proxy generator can use metadata, such as reflections 210 (shown in
For non-public enumerator types, the proxy generator can generate code by writing “enum {name}”, where {name} is the non-public name of the type, iterate through values of the enumerator, and write those values into the proxy enumerator definition.
For non-public class (and similarly for structure) with types, such as second class 220, the proxy generator can generate code by writing “class {name}”, where {name} is the non-public name of the type and iterate through each of the members contained by the class. These members can include constructors, such as first constructor 226, methods, such as second method 224, properties, fields, such as first field 222, indexers, and events.
For each member contained by a class, the proxy generator can perform other actions to continue writing the code. For properties and fields, for instance, the proxy generator generates get-accessors and set-accessors. For indexers, the proxy generator generates these get- and set-accessors as following: a header that has the original (e.g., non-public) types translated to the corresponding public proxy types; code to unwrap input parameters to convert them to original types; code to invocate a corresponding indexer of the original type; and code to wrap returned value and output parameters of the original types to the corresponding proxy types and return them as an output. For constructors, such as first constructor 226, the proxy generator generates: a header that has original types of arguments translated to corresponding proxy types; code to unwrap input parameters; code to create an object using a constructor of the original type; and code to wrap the output parameters. The reference to the newly created object of the original type is also stored as part of the object of the proxy type. For a method, such as second method 224, the proxy generator generates: a header that has original types of parameters translated to corresponding proxy types; code to unwrap input parameters; code to invocate the original type; and code to wrap a return value and output parameters of the original types into the corresponding proxy types and return them as an output.
In the ongoing embodiment, the proxy generator generates code for each of the non-public types of the production assembly. If second method 224, for instance, is represented in the production assembly by:
The proxy generator generates the following code, which is associated with the public proxy for second method 224:
The proxy generator can generate this code without user interaction for each non-public type in an assembly. With this code, a software developer can write simple, public calls into an application that are effective to call members of non-public types. In this example, rather than having to manually write the code immediately above to call second method 224, the developer can create objects of “namespaceMicrosoft.ProxyTypes.firstnamespace.secondclass” and call the second method.
In one implementation, the code generated by the proxy generator is built into an intermediary assembly. In the ongoing embodiment the proxy generator builds proxy assembly 206. Each non-public type of production assembly 202 is represented by a public proxy of the proxy assembly. Public types can also be represented in the proxy assembly, or they can instead by used directly from the production assembly. If the proxy assembly is to include public types, code associated with the public proxy for the public types can be included.
In the ongoing embodiment, the proxy assembly comprises members of the proxy types that can be called, which will in turn call the members of types in the production assembly. Each of the following members of the proxy types of the proxy assembly can, when called, call these listed members of the types of the production assembly: a first public proxy class 238 represents first class 214; a first method of public proxy 240 can call first method 216; a first property of public proxy 242 can call first property 218; a second public proxy class 244 represents second class 220; a first property of public proxy 246 can call first field 222; a second method of public proxy 248 can call second method 224; a first constructor 250 can call first constructor 226; a first public proxy structure 252 represents first structure 228; a third method of public proxy 254 can call third method 230; a first indexer of public proxy 256 can call first indexer 232; a first public proxy enumerator 258 represents first enumerator 234; and a first value of public proxy enumerator 260 represents first value 236.
If, by way of example, the public proxy of “namespaceMicrosoft.ProxyTypes.firstnamespace.secondclass” is called, the call is made to proxy assembly 206. This proxy assembly can then execute the code associated with the public proxy (shown above) to call and interact with the corresponding method of the non-public type in production assembly 202.
Unit Testing
Referring to
At block 402, a universal testing framework receives a testing assembly having a call to members of a public proxy. In one embodiment, the members of the public proxy contain code in proxy assembly 206. This code of the proxy assembly is capable of calling corresponding members of a non-public type in production assembly 202.
At block 404, the universal testing framework calls the public proxy, in this case by executing the testing assembly as an argument. In one embodiment, calling a public proxy initiates code in the proxy assembly that calls (and inputs data to) a member of a non-public type in a production assembly. The input can be provided by the testing assembly and be designed to test the member.
In the ongoing embodiment, the universal testing framework executes the testing assembly, thereby calling and sending testing data to the second method of the public proxy 248. By so doing, proxy assembly 206 executes calls and inputs testing data (as prescribed in the testing assembly) to second method 224 of production assembly 202. Second method 224 can be directed to receive this input, perform operations on the input, and provide output.
At block 406, the member of the public proxy type receives output. In the ongoing embodiment, the second method of the public proxy 248 receives output of the method 224, which it can send to the universal testing framework. This output and associated analysis can be received from or be a product of executing the testing assembly 208. Here the output is communicated from the production assembly to the proxy assembly. The proxy assembly then communicates this output to the testing assembly. The testing assembly analyzes this output and sends the output and/or its analysis to the universal testing framework.
At block 408, the universal testing framework presents the output and/or associated analysis. By so doing, a developer can be enabled to view and analyze the results in a user-friendly format.
The above-described tools enable an object having a non-public type in an assembly of managed code to be called as if the object's type is public. These tools can also enable a non-public member of a public or non-public type to be called as if the member is public. Although the invention has been described in language specific to structural features and/or methodological acts, it is to be understood that the invention defined in the appended claims is not necessarily limited to the specific features or acts described. Rather, the specific features and acts are disclosed as exemplary forms of implementing the claimed invention.